diff options
Diffstat (limited to 'tests/auto/qml')
408 files changed, 5321 insertions, 1086 deletions
diff --git a/tests/auto/qml/CMakeLists.txt b/tests/auto/qml/CMakeLists.txt index 9a674cd24a..5fe0b0950f 100644 --- a/tests/auto/qml/CMakeLists.txt +++ b/tests/auto/qml/CMakeLists.txt @@ -12,6 +12,12 @@ add_subdirectory(qjsvalueiterator) add_subdirectory(qjsonbinding) add_subdirectory(qqmlfile) add_subdirectory(qqmlfileselector) + +# Limit set of tests to run for static Qt builds. +if(QT_BUILD_MINIMAL_STATIC_TESTS) + return() +endif() + add_subdirectory(qqmlcomponent) add_subdirectory(qqmlconsole) add_subdirectory(qqmlengine) @@ -21,7 +27,9 @@ add_subdirectory(qqmlinfo) add_subdirectory(qqmllistreference) add_subdirectory(qqmllocale) add_subdirectory(qqmlmetaobject) -add_subdirectory(qqmlmoduleplugin) +if(NOT ANDROID) # QTBUG-100003 + add_subdirectory(qqmlmoduleplugin) +endif() add_subdirectory(qqmlnotifier) add_subdirectory(qqmlqt) add_subdirectory(qqmlxmlhttprequest) @@ -30,10 +38,23 @@ add_subdirectory(qtqmlmodules) add_subdirectory(qquickfolderlistmodel) add_subdirectory(qqmlapplicationengine) add_subdirectory(qqmlsettings) -add_subdirectory(qmldiskcache) + +if(NOT INTEGRITY) +# There's no mounted filesystem on INTEGRITY therefore skipping qmldiskcache + add_subdirectory(qmldiskcache) +endif() + add_subdirectory(qqmlmetatype) add_subdirectory(qmlcompiler_manual) -add_subdirectory(qmlbasicapp) +if(TARGET Qt::Quick) + # This test always creates static plugins. To avoid linker command line + # ordering issues, we need at least CMake 3.21 and we cannot include the + # test if qmlimportscanner is being built as part of the main project. + if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.21 AND + (QT_BUILD_STANDALONE_TESTS OR QT6_IS_SHARED_LIBS_BUILD)) + add_subdirectory(qmlbasicapp) + endif() +endif() if(TARGET Qt::Widgets) add_subdirectory(qjsengine) add_subdirectory(qjsvalue) @@ -42,19 +63,20 @@ endif() if(QT_FEATURE_process AND QT_FEATURE_qml_debug) add_subdirectory(debugger) endif() -if(QT_FEATURE_process AND NOT boot2qt) +if(QT_FEATURE_process AND NOT CMAKE_CROSSCOMPILING) add_subdirectory(qmlformat) add_subdirectory(qmlimportscanner) add_subdirectory(qmllint) add_subdirectory(qmlplugindump) endif() -if(QT_FEATURE_library) +if(QT_FEATURE_library AND NOT ANDROID) + # QTBUG-100169 add_subdirectory(qqmlextensionplugin) endif() if(QT_FEATURE_private_tests) add_subdirectory(qqmlcpputils) add_subdirectory(qqmldirparser) - if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.19") + if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.19" AND QT_FEATURE_process) # Calls qt6_target_qml_sources() directly, which needs CMake 3.19+ add_subdirectory(qmlcachegen) endif() @@ -100,7 +122,9 @@ if(QT_FEATURE_private_tests) add_subdirectory(qv4mm) add_subdirectory(qv4identifiertable) add_subdirectory(qv4regexp) - add_subdirectory(ecmascripttests) + if(QT_FEATURE_process AND NOT QNX) + add_subdirectory(ecmascripttests) + endif() add_subdirectory(bindingdependencyapi) add_subdirectory(v4misc) add_subdirectory(qqmldelegatemodel) # special case diff --git a/tests/auto/qml/bindingdependencyapi/CMakeLists.txt b/tests/auto/qml/bindingdependencyapi/CMakeLists.txt index 775160e4c5..12ca578d93 100644 --- a/tests/auto/qml/bindingdependencyapi/CMakeLists.txt +++ b/tests/auto/qml/bindingdependencyapi/CMakeLists.txt @@ -12,16 +12,14 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_bindingdependencyapi SOURCES - ../../shared/util.cpp ../../shared/util.h tst_bindingdependencyapi.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/bindingdependencyapi/dummy_imports.qml b/tests/auto/qml/bindingdependencyapi/dummy_imports.qml index b9a196e188..63d33cbea6 100644 --- a/tests/auto/qml/bindingdependencyapi/dummy_imports.qml +++ b/tests/auto/qml/bindingdependencyapi/dummy_imports.qml @@ -1,8 +1,7 @@ // This file exists for the sole purpose for qmlimportscanner to find // which modules it needs to extract for deployment. -// Otherwise, it fails to find the imports that are expressed in C++ -// code in tst_parserstress.cpp +// Otherwise, it fails to find the imports that are expressed in C++. -import QtQuick 2.0 +import QtQuick -QtObject { } // This is needed in order to keep importscanner happy +QtObject { } diff --git a/tests/auto/qml/bindingdependencyapi/tst_bindingdependencyapi.cpp b/tests/auto/qml/bindingdependencyapi/tst_bindingdependencyapi.cpp index 82c997a5b8..81162c2c8a 100644 --- a/tests/auto/qml/bindingdependencyapi/tst_bindingdependencyapi.cpp +++ b/tests/auto/qml/bindingdependencyapi/tst_bindingdependencyapi.cpp @@ -32,7 +32,6 @@ #include <private/qqmlbinding_p.h> #include <QtQuick/private/qquicktext_p.h> #include <QtQuick/private/qquickrectangle_p.h> -#include "../../shared/util.h" #include <qqmlcontext.h> class tst_bindingdependencyapi : public QObject @@ -49,6 +48,7 @@ private slots: void testConditionalDependencies_data(); void testConditionalDependencies(); void testBindingLoop(); + void testQproperty(); private: bool findProperties(const QVector<QQmlProperty> &properties, QObject *obj, const QString &propertyName, const QVariant &value); @@ -355,6 +355,36 @@ void tst_bindingdependencyapi::testBindingLoop() delete rect; } +void tst_bindingdependencyapi::testQproperty() +{ + QQmlEngine engine; + QQmlComponent c(&engine); + c.setData(QByteArray("import QtQuick 2.0\n" + "Item {\n" + "id: root\n" + "Text {\n" + "id: label\n" + "text: root.x\n" + "}\n" + "}"), QUrl()); + QScopedPointer<QObject> root(c.create()); + QVERIFY(!root.isNull()); + QObject *text = root->findChildren<QQuickText *>().front(); + QVERIFY(text); + auto data = QQmlData::get(text); + QVERIFY(data); + auto b = data->bindings; + QVERIFY(b); + auto binding = dynamic_cast<QQmlBinding*>(b); + QVERIFY(binding); + auto dependencies = binding->dependencies(); + QCOMPARE(dependencies.size(), 1); + auto dependency = dependencies.front(); + QVERIFY(dependency.isValid()); + QCOMPARE(quintptr(dependency.object()), quintptr(root.get())); + QCOMPARE(dependency.property().name(), "x"); +} + QTEST_MAIN(tst_bindingdependencyapi) #include "tst_bindingdependencyapi.moc" diff --git a/tests/auto/qml/debugger/CMakeLists.txt b/tests/auto/qml/debugger/CMakeLists.txt index b6558ac5c1..a8bb089e15 100644 --- a/tests/auto/qml/debugger/CMakeLists.txt +++ b/tests/auto/qml/debugger/CMakeLists.txt @@ -1,25 +1,29 @@ # Generated from debugger.pro. add_subdirectory(qqmldebugjsserver) -add_subdirectory(qdebugmessageservice) - add_subdirectory(qqmldebugtranslationservice) -add_subdirectory(qqmldebugtranslationclient) - -add_subdirectory(qqmlenginedebugservice) -add_subdirectory(qqmldebugjs) -add_subdirectory(qqmlinspector) -add_subdirectory(qqmlprofilerservice) add_subdirectory(qpacketprotocol) -add_subdirectory(qqmlenginedebuginspectorintegrationtest) -add_subdirectory(qqmlenginecontrol) -add_subdirectory(qqmldebuggingenabler) add_subdirectory(qqmlnativeconnector) -add_subdirectory(qqmldebugprocess) -add_subdirectory(qqmlpreview) + +if(NOT (CMAKE_CROSSCOMPILING OR (MACOS AND TEST_architecture_arch STREQUAL "x86_64"))) + add_subdirectory(qdebugmessageservice) + add_subdirectory(qqmldebugtranslationclient) + add_subdirectory(qqmlenginedebugservice) + add_subdirectory(qqmldebugjs) + add_subdirectory(qqmlinspector) + add_subdirectory(qqmlprofilerservice) + add_subdirectory(qqmlenginedebuginspectorintegrationtest) + add_subdirectory(qqmlenginecontrol) + add_subdirectory(qqmldebuggingenabler) + add_subdirectory(qqmldebugprocess) + add_subdirectory(qqmlpreview) +endif() + if(QT_FEATURE_private_tests) add_subdirectory(qqmldebugclient) add_subdirectory(qqmldebuglocal) - add_subdirectory(qqmldebugservice) add_subdirectory(qv4debugger) + if(NOT (CMAKE_CROSSCOMPILING OR (MACOS AND TEST_architecture_arch STREQUAL "x86_64"))) + add_subdirectory(qqmldebugservice) + endif() endif() diff --git a/tests/auto/qml/debugger/qdebugmessageservice/CMakeLists.txt b/tests/auto/qml/debugger/qdebugmessageservice/CMakeLists.txt index 3ad886b0ad..f6c4af80d1 100644 --- a/tests/auto/qml/debugger/qdebugmessageservice/CMakeLists.txt +++ b/tests/auto/qml/debugger/qdebugmessageservice/CMakeLists.txt @@ -12,19 +12,16 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qdebugmessageservice SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h tst_qdebugmessageservice.cpp - INCLUDE_DIRECTORIES - ../../../shared - ../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::Network Qt::QmlDebugPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp index ecee0db428..d0aeefdacc 100644 --- a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp +++ b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp @@ -27,7 +27,7 @@ ****************************************************************************/ //QQmlDebugTest -#include "debugutil_p.h" +#include "../shared/debugutil_p.h" #include <private/qqmldebugclient_p.h> #include <private/qqmldebugconnection_p.h> @@ -44,6 +44,9 @@ class tst_QDebugMessageService : public QQmlDebugTest { Q_OBJECT +public: + tst_QDebugMessageService(); + private slots: void retrieveDebugOutput(); @@ -133,6 +136,11 @@ QList<QQmlDebugClient *> tst_QDebugMessageService::createClients() return QList<QQmlDebugClient *>({m_client}); } +tst_QDebugMessageService::tst_QDebugMessageService() + : QQmlDebugTest(QT_QMLTEST_DATADIR) +{ +} + void tst_QDebugMessageService::retrieveDebugOutput() { QCOMPARE(QQmlDebugTest::connectTo(QLibraryInfo::path(QLibraryInfo::BinariesPath) + "/qml", diff --git a/tests/auto/qml/debugger/qpacketprotocol/CMakeLists.txt b/tests/auto/qml/debugger/qpacketprotocol/CMakeLists.txt index 3ab44c2670..28708ff48b 100644 --- a/tests/auto/qml/debugger/qpacketprotocol/CMakeLists.txt +++ b/tests/auto/qml/debugger/qpacketprotocol/CMakeLists.txt @@ -6,12 +6,10 @@ qt_internal_add_test(tst_qpacketprotocol SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h tst_qpacketprotocol.cpp INCLUDE_DIRECTORIES - ../../../shared ../shared PUBLIC_LIBRARIES Qt::CorePrivate @@ -19,6 +17,7 @@ qt_internal_add_test(tst_qpacketprotocol Qt::GuiPrivate Qt::Network Qt::QmlDebugPrivate + Qt::QuickTestUtilsPrivate ) ## Scopes: diff --git a/tests/auto/qml/debugger/qqmldebugclient/CMakeLists.txt b/tests/auto/qml/debugger/qqmldebugclient/CMakeLists.txt index 86009707a9..50089a4d57 100644 --- a/tests/auto/qml/debugger/qqmldebugclient/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmldebugclient/CMakeLists.txt @@ -6,7 +6,6 @@ qt_internal_add_test(tst_qqmldebugclient SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h ../shared/qqmldebugtestservice.cpp ../shared/qqmldebugtestservice.h @@ -15,7 +14,6 @@ qt_internal_add_test(tst_qqmldebugclient QT_QML_DEBUG QT_QML_DEBUG_NO_WARNING INCLUDE_DIRECTORIES - ../../../shared ../shared PUBLIC_LIBRARIES Qt::CorePrivate @@ -23,6 +21,7 @@ qt_internal_add_test(tst_qqmldebugclient Qt::GuiPrivate Qt::QmlDebugPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate ) ## Scopes: diff --git a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/CMakeLists.txt b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/CMakeLists.txt index 8b3f0b6d5c..ae0f5f5b40 100644 --- a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/CMakeLists.txt @@ -6,12 +6,10 @@ qt_internal_add_test(tst_qqmldebuggingenabler SOURCES - ../../../../shared/util.cpp ../../../../shared/util.h ../../shared/debugutil.cpp ../../shared/debugutil_p.h ../../shared/qqmldebugprocess.cpp ../../shared/qqmldebugprocess_p.h tst_qqmldebuggingenabler.cpp INCLUDE_DIRECTORIES - ../../../../shared ../../shared PUBLIC_LIBRARIES Qt::CorePrivate @@ -19,6 +17,7 @@ qt_internal_add_test(tst_qqmldebuggingenabler Qt::GuiPrivate Qt::Qml Qt::QmlDebugPrivate + Qt::QuickTestUtilsPrivate ) #### Keys ignored in scope 1:.:.:qqmldebuggingenabler.pro:<TRUE>: diff --git a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp index a22ae6e7a0..163a9e2e7e 100644 --- a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp +++ b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp @@ -28,7 +28,7 @@ #include "debugutil_p.h" #include "qqmldebugprocess_p.h" -#include "../../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <private/qqmldebugclient_p.h> #include <private/qqmldebugconnection_p.h> @@ -47,6 +47,9 @@ class tst_QQmlDebuggingEnabler : public QQmlDebugTest { Q_OBJECT +public: + tst_QQmlDebuggingEnabler(); + private slots: void qmlscene_data(); void qmlscene(); @@ -91,6 +94,11 @@ void tst_QQmlDebuggingEnabler::data() } } +tst_QQmlDebuggingEnabler::tst_QQmlDebuggingEnabler() + : QQmlDebugTest(QT_QMLTEST_DATADIR) +{ +} + void tst_QQmlDebuggingEnabler::qmlscene_data() { data(); diff --git a/tests/auto/qml/debugger/qqmldebugjs/CMakeLists.txt b/tests/auto/qml/debugger/qqmldebugjs/CMakeLists.txt index 99a885589e..8741902c8e 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmldebugjs/CMakeLists.txt @@ -12,18 +12,17 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmldebugjs SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h tst_qqmldebugjs.cpp INCLUDE_DIRECTORIES - ../../../shared - ../shared ../shared + ../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlDebugPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp index 41c0c5ec00..82f76ca30d 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp +++ b/tests/auto/qml/debugger/qqmldebugjs/tst_qqmldebugjs.cpp @@ -28,7 +28,7 @@ #include "debugutil_p.h" #include "qqmldebugprocess_p.h" -#include "../../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <private/qqmlenginedebugclient_p.h> #include <private/qv4debugclient_p.h> @@ -82,6 +82,9 @@ class tst_QQmlDebugJS : public QQmlDebugTest { Q_OBJECT +public: + tst_QQmlDebugJS(); + private slots: void initTestCase() override; @@ -175,6 +178,11 @@ private: }; +tst_QQmlDebugJS::tst_QQmlDebugJS() + : QQmlDebugTest(QT_QMLTEST_DATADIR) +{ +} + void tst_QQmlDebugJS::initTestCase() { QQmlDebugTest::initTestCase(); diff --git a/tests/auto/qml/debugger/qqmldebuglocal/CMakeLists.txt b/tests/auto/qml/debugger/qqmldebuglocal/CMakeLists.txt index 80836f5f6a..0458b076dc 100644 --- a/tests/auto/qml/debugger/qqmldebuglocal/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmldebuglocal/CMakeLists.txt @@ -6,7 +6,6 @@ qt_internal_add_test(tst_qqmldebuglocal SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h ../shared/qqmldebugtestservice.cpp ../shared/qqmldebugtestservice.h @@ -14,7 +13,6 @@ qt_internal_add_test(tst_qqmldebuglocal DEFINES QT_QML_DEBUG_NO_WARNING INCLUDE_DIRECTORIES - ../../../shared ../shared PUBLIC_LIBRARIES Qt::CorePrivate @@ -22,6 +20,7 @@ qt_internal_add_test(tst_qqmldebuglocal Qt::GuiPrivate Qt::QmlDebugPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate ) ## Scopes: diff --git a/tests/auto/qml/debugger/qqmldebugservice/CMakeLists.txt b/tests/auto/qml/debugger/qqmldebugservice/CMakeLists.txt index 7434dc4286..1642c71d93 100644 --- a/tests/auto/qml/debugger/qqmldebugservice/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmldebugservice/CMakeLists.txt @@ -12,7 +12,6 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmldebugservice SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h ../shared/qqmldebugtestservice.cpp ../shared/qqmldebugtestservice.h @@ -20,7 +19,6 @@ qt_internal_add_test(tst_qqmldebugservice DEFINES QT_QML_DEBUG_NO_WARNING INCLUDE_DIRECTORIES - ../../../shared ../shared PUBLIC_LIBRARIES Qt::CorePrivate @@ -28,6 +26,7 @@ qt_internal_add_test(tst_qqmldebugservice Qt::GuiPrivate Qt::QmlDebugPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp index b90844bd10..d36ae80aa5 100644 --- a/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp +++ b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp @@ -30,7 +30,7 @@ #include "qqmldebugtestservice.h" #include "debugutil_p.h" #include "qqmldebugprocess_p.h" -#include "../../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <private/qqmldebugclient_p.h> #include <private/qqmldebugconnection_p.h> @@ -51,6 +51,9 @@ class tst_QQmlDebugService : public QQmlDataTest { Q_OBJECT +public: + tst_QQmlDebugService(); + private: QQmlDebugConnection *m_conn; QQmlDebugTestService *m_service; @@ -69,6 +72,11 @@ private slots: void checkSupportForOldDataStreamVersion(); }; +tst_QQmlDebugService::tst_QQmlDebugService() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_QQmlDebugService::initTestCase() { QQmlDataTest::initTestCase(); diff --git a/tests/auto/qml/debugger/qqmldebugtranslationclient/CMakeLists.txt b/tests/auto/qml/debugger/qqmldebugtranslationclient/CMakeLists.txt index 8d7a9b38c2..699a6adc7e 100644 --- a/tests/auto/qml/debugger/qqmldebugtranslationclient/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmldebugtranslationclient/CMakeLists.txt @@ -10,13 +10,11 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmldebugtranslationclient SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h tst_qqmldebugtranslationclient.cpp INCLUDE_DIRECTORIES ../../../../../src/plugins/qmltooling/qmldbg_preview - ../../../shared ../shared PUBLIC_LIBRARIES Qt::QuickPrivate @@ -25,6 +23,7 @@ qt_internal_add_test(tst_qqmldebugtranslationclient Qt::GuiPrivate Qt::Network Qt::QmlDebugPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/debugger/qqmldebugtranslationclient/tst_qqmldebugtranslationclient.cpp b/tests/auto/qml/debugger/qqmldebugtranslationclient/tst_qqmldebugtranslationclient.cpp index 7bdf4a02f1..1c73eb8521 100644 --- a/tests/auto/qml/debugger/qqmldebugtranslationclient/tst_qqmldebugtranslationclient.cpp +++ b/tests/auto/qml/debugger/qqmldebugtranslationclient/tst_qqmldebugtranslationclient.cpp @@ -54,6 +54,10 @@ class tst_QQmlDebugTranslationClient : public QQmlDebugTest { Q_OBJECT public: + tst_QQmlDebugTranslationClient() + : QQmlDebugTest(QT_QMLTEST_DATADIR) + { + } private slots: void init() @@ -71,7 +75,7 @@ private slots: { QVersionedPacket<QQmlDebugConnector> packet; m_debugTranslationClient->sendMessage( - QQmlDebugTranslation::createMissingTranslationsRequest(packet)); + QQmlDebugTranslation::createTranslationIssuesRequest(packet)); QTRY_VERIFY(m_debugTranslationClient->translationIssues.size() > 0); } diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/BLACKLIST b/tests/auto/qml/debugger/qqmldebugtranslationservice/BLACKLIST new file mode 100644 index 0000000000..b572260e87 --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/BLACKLIST @@ -0,0 +1,7 @@ +# QTBUG-100164 +[verifyCorrectNumberOfMissingTranslations] +android +[getElideWarnings] +android +[getElideWarningsWhenStateChanged] +android diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/CMakeLists.txt b/tests/auto/qml/debugger/qqmldebugtranslationservice/CMakeLists.txt index 6c6ddcfb62..ae112c7c94 100644 --- a/tests/auto/qml/debugger/qqmldebugtranslationservice/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/CMakeLists.txt @@ -10,7 +10,6 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmldebugtranslationservice SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h tst_qqmldebugtranslationservice.cpp @@ -18,7 +17,6 @@ qt_internal_add_test(tst_qqmldebugtranslationservice QT_QML_DEBUG INCLUDE_DIRECTORIES ../../../../../src/plugins/qmltooling/qmldbg_preview - ../../../shared ../shared PUBLIC_LIBRARIES Qt::Quick @@ -29,6 +27,7 @@ qt_internal_add_test(tst_qqmldebugtranslationservice Qt::Network Qt::Qml Qt::QmlDebugPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_es.qm b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_es.qm Binary files differindex 8d8064cc55..75ecfc87f3 100644 --- a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_es.qm +++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_es.qm diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_es.ts b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_es.ts index e8d675ec0d..a4e8e96c57 100644 --- a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_es.ts +++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_es.ts @@ -2,16 +2,26 @@ <!DOCTYPE TS> <TS version="2.1" language="es_ES"> <context> - <name>test</name> - <message> - <location filename="../test.qml" line="43"/> - <source>hello</source> + <name></name> + <message id="TRID_1"> + <source>TRID_1</source> <translation>hola</translation> </message> - <message> - <location filename="../test.qml" line="49"/> - <source>short</source> - <translation type="unfinished"></translation> + <message id="TRID_2"> + <source>TRID_2</source> + <translation>long text in spanish</translation> + </message> + <message id="TRID_3"> + <source>TRID_3</source> + <translation>spanish</translation> + </message> + <message id="TRID_4"> + <source>TRID_4</source> + <translation>has it</translation> + </message> + <message id="TRID_5"> + <source>TRID_5</source> + <translation>all !</translation> </message> </context> </TS> diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_fr.qm b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_fr.qm Binary files differindex 273539d28a..4bc491c34f 100644 --- a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_fr.qm +++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_fr.qm diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_fr.ts b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_fr.ts index fd4b8f5649..b64fee2744 100644 --- a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_fr.ts +++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/i18n/qml_fr.ts @@ -2,15 +2,25 @@ <!DOCTYPE TS> <TS version="2.1" language="fr_FR"> <context> - <name>test</name> - <message> - <location filename="../test.qml" line="43"/> - <source>hello</source> + <name></name> + <message id="TRID_1"> + <source>TRID_1</source> <translation>bonjour</translation> </message> - <message> - <location filename="../test.qml" line="49"/> - <source>short</source> + <message id="TRID_2"> + <source>TRID_2</source> + <translation>french misses some</translation> + </message> + <message id="TRID_3"> + <source>TRID_3</source> + <translation></translation> + </message> + <message id="TRID_4"> + <source>TRID_4</source> + <translation>TRID_4</translation> + </message> + <message id="TRID_5"> + <source>TRID_5</source> <translation type="unfinished"></translation> </message> </context> diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml index 325d8cdca5..1834ed3772 100644 --- a/tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml +++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/data/test.qml @@ -26,40 +26,48 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick - -Item { +Rectangle { id: root - width: 360 - height: 360 + width: 130 + height: 200 property int widthFactor: 7 Column { + anchors.fill: parent Text { id: text1 - text: qsTr("hello") - width: root.width / widthFactor + width: parent.width; + text: qsTrId("TRID_1") } Text { id: text2 - text: qsTr("short") - width: root.width / widthFactor + width: 100; + text: qsTrId("TRID_2") } Text { id: text3 - text: "long not translated text" - width: root.width / widthFactor + width: parent.width; + text: qsTrId("TRID_3") + } + Text { + id: text4 + width: parent.width; + text: qsTrId("TRID_4") + } + Text { + id: text5 + width: parent.width; + text: qsTrId("TRID_5") + } + Text { + id: text6 + width: parent.width; + text: "way too long not translated text that should elide but not be marked" } } - // this is necessary to have the test working for different font sizes and dpi settings - Text { - id: originHelloTextToGetTheNecessaryWidth - text: "short" - opacity: 0 - anchors.bottom: root.bottom - onWidthChanged: root.width = originHelloTextToGetTheNecessaryWidth.width * widthFactor - } + states: [ State { name: "BiggerFontState" @@ -79,10 +87,6 @@ Item { font.pointSize: 20 } - PropertyChanges { - target: originHelloTextToGetTheNecessaryWidth - font.pointSize: 20 - } }, State { name: "WayBiggerFontState" @@ -101,11 +105,6 @@ Item { target: text3 font.pointSize: 30 } - - PropertyChanges { - target: originHelloTextToGetTheNecessaryWidth - font.pointSize: 30 - } } ] } diff --git a/tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp b/tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp index b2b0ee4661..6d9be9deab 100644 --- a/tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp +++ b/tests/auto/qml/debugger/qqmldebugtranslationservice/tst_qqmldebugtranslationservice.cpp @@ -61,6 +61,7 @@ class tst_QQmlDebugTranslationService : public QQmlDebugTest Q_OBJECT public: tst_QQmlDebugTranslationService() + : QQmlDebugTest(QT_QMLTEST_DATADIR) { } @@ -71,8 +72,6 @@ private slots: m_view.setSource((testFileUrl(QMLFILE))); QTRY_VERIFY2(m_view.status() == QQuickView::Ready, "Failed to load QML file"); - m_view.show(); - QVERIFY(QTest::qWaitForWindowActive(&m_view)); initQtHooks(); QVERIFY(hooks->qt_qmlDebugEnableService(qPrintable(QQmlDebugTranslationServiceImpl::s_key))); } @@ -83,146 +82,80 @@ private slots: QVERIFY(currentDebugServiceMessage().isEmpty()); } - void changeLanguage(const QString &language = QLocale::system().uiLanguages().first()) + void verifyMissingAllTranslationsForMissingLanguage() { - // only necessary for visual debugging - // QTest::qWait(500); - - QVersionedPacket<QQmlDebugConnector> packet; - sendMessageToService(createChangeLanguageRequest(packet, dataDirectoryUrl(), language)); - - // check without any eventloop cycle it should be still empty - QCOMPARE(currentDebugServiceMessage(), QByteArray()); + changeLanguage("ru"); + auto translationIssues = getTranslationIssues(); - QVersionedPacket<QQmlDebugConnector> expectedReply; - expectedReply << Reply::LanguageChanged; - QCOMPARE(currentReply().at(0), expectedReply.data()); - // clear buffer explicit, because it is used in other test methods as helper method aswell - hooks->qt_qmlDebugClearBuffer(); - QVERIFY(currentDebugServiceMessage().isEmpty()); + QCOMPARE(translationIssues.length(), getTranslatableTextOccurrences().count()); + QCOMPARE(translationIssues.at(0).language, "ru ru-RU ru-Cyrl-RU"); } - void streamTranslationIssues() + void verifyCorrectNumberOfMissingTranslations() { - TranslationIssue issue; - issue.type = TranslationIssue::Type::Missing; - CodeMarker codeMarker; - codeMarker.url = "url"; - codeMarker.line = 8; - codeMarker.column = 9; - issue.codeMarker = codeMarker; - issue.language = "language"; - QVersionedPacket<QQmlDebugConnector> writePacket; - writePacket << Reply::MissingTranslations - << QVector<TranslationIssue>{issue}; - Reply replyType; - QVector<TranslationIssue> replyTranslationIssues; - QVersionedPacket<QQmlDebugConnector> readPacket(writePacket.data()); - readPacket >> replyType; + changeLanguage("fr"); - readPacket >> replyTranslationIssues; + auto translationIssues = getTranslationIssues(); - QCOMPARE(replyTranslationIssues.at(0), issue); + QCOMPARE(translationIssues.length(), 3); + QCOMPARE(translationIssues.at(0).language, "fr fr-FR fr-Latn-FR"); } - void missingAllTranslations() + void verifyCorrectNumberOfTranslatableTextOccurrences() { - changeLanguage("ru"); - - QVersionedPacket<QQmlDebugConnector> packet; - sendMessageToService(createMissingTranslationsRequest(packet)); - const QList<QByteArray> replyMessages = currentReply(); - - TranslationIssue firstMissingTranslationLine; - firstMissingTranslationLine.type = TranslationIssue::Type::Missing; - CodeMarker codeMarker; - codeMarker.url = testFileUrl(QMLFILE); - codeMarker.line = 41; - codeMarker.column = 19; - firstMissingTranslationLine.codeMarker = codeMarker; - firstMissingTranslationLine.language = "ru ru-RU ru-Cyrl-RU"; - TranslationIssue secondMissingTranslationLine; - secondMissingTranslationLine.type = TranslationIssue::Type::Missing; - codeMarker.url = testFileUrl(QMLFILE); - codeMarker.line = 46; - codeMarker.column = 19; - secondMissingTranslationLine.codeMarker = codeMarker; - secondMissingTranslationLine.language = "ru ru-RU ru-Cyrl-RU"; - QVersionedPacket<QQmlDebugConnector> expectedReply; - expectedReply << Reply::MissingTranslations - << QVector<TranslationIssue>{firstMissingTranslationLine, secondMissingTranslationLine}; - - QVERIFY2(replyMessages.at(0) == expectedReply.data(), qPrintable(debugReply(replyMessages))); + QCOMPARE(getTranslatableTextOccurrences().length(), 5); } - void missingOneTranslation() + void verifyCorrectNumberOfStates() { - changeLanguage("fr"); - - QVersionedPacket<QQmlDebugConnector> packet; - sendMessageToService(createMissingTranslationsRequest(packet)); - const QList<QByteArray> replyMessages = currentReply(); - - - TranslationIssue missingTranslationLine; - missingTranslationLine.type = TranslationIssue::Type::Missing; - CodeMarker codeMarker; - codeMarker.url = testFileUrl(QMLFILE); - codeMarker.line = 46; - codeMarker.column = 19; - missingTranslationLine.codeMarker = codeMarker; - missingTranslationLine.language = "fr fr-FR fr-Latn-FR"; - QVersionedPacket<QQmlDebugConnector> expectedReply; - expectedReply << Reply::MissingTranslations - << QVector<TranslationIssue>{missingTranslationLine}; - - QVERIFY2(replyMessages.at(0) == expectedReply.data(), qPrintable(debugReply(replyMessages))); + QCOMPARE(getStates().length(), 2); } - void getTranslatableTextOccurrences() + void getElideWarnings() { - QVersionedPacket<QQmlDebugConnector> packet; - sendMessageToService(createTranslatableTextOccurrencesRequest(packet)); - QVersionedPacket<QQmlDebugConnector> readPacket(currentReply().at(0)); + sendMessageToService(createWatchTextElidesRequest(packet)); - Reply replyType; - QVector<QmlElement> replyQmlElementList; - readPacket >> replyType; - readPacket >> replyQmlElementList; - QCOMPARE(replyQmlElementList.count(), 2); + changeLanguage("es"); + auto translationIssues = getTranslationIssues(); + + int elideWarningCount = 0; + for (auto issue : translationIssues) { + if (issue.type == TranslationIssue::Type::Elided) { + elideWarningCount++; + } + } + QCOMPARE(elideWarningCount, 1); } - void getStates() + void getElideWarningsWhenStateChanged() { - QVersionedPacket<QQmlDebugConnector> packet; - sendMessageToService(createStateListRequest(packet)); - QVersionedPacket<QQmlDebugConnector> readPacket(currentReply().at(0)); + sendMessageToService(createWatchTextElidesRequest(packet)); - Reply replyType; - QVector<QmlState> replyStateList; - readPacket >> replyType; - readPacket >> replyStateList; - QCOMPARE(replyStateList.count(), 2); + changeLanguage("es"); + + sendMessageToService(createChangeStateRequest(packet, "WayBiggerFontState")); + + auto translationIssues = getTranslationIssues(); + + int elideWarningCount = 0; + for (auto issue : translationIssues) { + if (issue.type == TranslationIssue::Type::Elided) { + elideWarningCount++; + } + } + QCOMPARE(elideWarningCount, 1); } void loopThroughAllStates() { + QVector<QmlState> stateList = getStates(); - QVersionedPacket<QQmlDebugConnector> packet; - sendMessageToService(createStateListRequest(packet)); - QVersionedPacket<QQmlDebugConnector> readPacket(currentReply().at(0)); - - Reply replyType; - QVector<QmlState> replyStateList; - readPacket >> replyType; - readPacket >> replyStateList; - QCOMPARE(replyStateList.count(), 2); + QCOMPARE(stateList.length(), 2); - for (int i = 0; i < replyStateList.count(); i++) { - auto stateName = replyStateList.at(i).name; - hooks->qt_qmlDebugClearBuffer(); + for (int i = 0; i < stateList.count(); i++) { + auto stateName = stateList.at(i).name; QVersionedPacket<QQmlDebugConnector> packet; sendMessageToService(createChangeStateRequest(packet, stateName)); @@ -238,121 +171,61 @@ private slots: } } - void getElideWarning() +private: + + QVector<QmlElement> getTranslatableTextOccurrences() { + QVersionedPacket<QQmlDebugConnector> packet; + sendMessageToService(createTranslatableTextOccurrencesRequest(packet)); + QVersionedPacket<QQmlDebugConnector> readPacket(currentReply().at(0)); - changeLanguage("fr"); + Reply replyType; + QVector<QmlElement> qmlElementList; + readPacket >> replyType; + readPacket >> qmlElementList; - QVersionedPacket<QQmlDebugConnector> packet; - sendMessageToService(createWatchTextElidesRequest(packet)); - const QList<QByteArray> replyMessages = currentReply(); - - - const QByteArray reply1 = replyMessages.at(0); - - TranslationIssue elidedeTextLine; - elidedeTextLine.type = TranslationIssue::Type::Elided; - CodeMarker codeMarker; - codeMarker.url = testFileUrl(QMLFILE); - codeMarker.line = 41; - codeMarker.column = 19; - elidedeTextLine.codeMarker = codeMarker; - elidedeTextLine.language = "fr fr-FR fr-Latn-FR"; - QVersionedPacket<QQmlDebugConnector> expectedTextElidedReply; - expectedTextElidedReply << Reply::TextElided << elidedeTextLine; - - Reply replyType1; - TranslationIssue replyTranslationIssue; - QVersionedPacket<QQmlDebugConnector> readPacket1(reply1); - readPacket1 >> replyType1; - readPacket1 >> replyTranslationIssue; - QVERIFY2(reply1 == expectedTextElidedReply.data(), qPrintable(debugReply(replyMessages))); - - { - gotMessage = false; - auto handler = qInstallMessageHandler(messageHandler); - auto guard = qScopeGuard([&]() { qInstallMessageHandler(handler); }); - - packet.clear(); - sendMessageToService(createDisableWatchTextElidesRequest(packet)); - QTRY_VERIFY(gotMessage); - } + return qmlElementList; } - void getElideWarningsWhenStateChanged() + QVector<QmlState> getStates() { - // it is only eliding in fr - changeLanguage("fr"); QVersionedPacket<QQmlDebugConnector> packet; - sendMessageToService(createWatchTextElidesRequest(packet)); - const QString stateName("BiggerFontState"); - - packet.clear(); - - sendMessageToService(createChangeStateRequest(packet, stateName)); - - QList<QByteArray> replyMessagesWithElideWarnings; - - QByteArray stateChangedReply; - while (stateChangedReply.isEmpty()) { - for (const auto &reply : currentReply()) { - QVersionedPacket<QQmlDebugConnector> packet(reply); - Reply replyType; - packet >> replyType; - - if (replyType == Reply::StateChanged) - stateChangedReply = reply; - else - replyMessagesWithElideWarnings.append(replyMessagesWithElideWarnings); - } - hooks->qt_qmlDebugClearBuffer(); - } + sendMessageToService(createStateListRequest(packet)); + auto replies = currentReply(); + QVersionedPacket<QQmlDebugConnector> readPacket(replies.at(0)); - TranslationIssue expectedTranslationIssue; - expectedTranslationIssue.type = TranslationIssue::Type::Elided; - CodeMarker codeMarker; - codeMarker.url = testFileUrl(QMLFILE); - codeMarker.line = 41; - codeMarker.column = 19; - expectedTranslationIssue.codeMarker = codeMarker; - expectedTranslationIssue.language = "fr fr-FR fr-Latn-FR"; - - // text size is calculated many times, so it could be that we get - // the same warning many times - for (const QByteArray &message : replyMessagesWithElideWarnings) { - Reply replyType; - TranslationIssue translationIssue; - QVersionedPacket<QQmlDebugConnector> readPacket1(message); - readPacket1 >> replyType; - readPacket1 >> translationIssue; - QCOMPARE(replyType, Reply::TextElided); - QVERIFY2(expectedTranslationIssue == translationIssue, - qPrintable(debugReply(replyMessagesWithElideWarnings))); + Reply replyType; + QVector<QmlState> stateList; + readPacket >> replyType; + readPacket >> stateList; - } + return stateList; + } - QVersionedPacket<QQmlDebugConnector> expectedStateChangedReply; - expectedStateChangedReply << Reply::StateChanged << stateName; + void changeLanguage(const QString &language = QLocale::system().uiLanguages().first()) + { + QVersionedPacket<QQmlDebugConnector> packet; + sendMessageToService(createChangeLanguageRequest(packet, dataDirectoryUrl(), language)); + QVersionedPacket<QQmlDebugConnector> readPacket(currentReply().at(0)); - Reply replyType2; - QString stateNameReply; - QVersionedPacket<QQmlDebugConnector> readPacket2(stateChangedReply); - readPacket2 >> replyType2 >> stateNameReply; - QCOMPARE(stateChangedReply, expectedStateChangedReply.data()); + // Use this for visual debugging + // QTest::qWait(500); + } - { - gotMessage = false; - auto handler = qInstallMessageHandler(messageHandler); - auto guard = qScopeGuard([&]() { qInstallMessageHandler(handler); }); + QVector<TranslationIssue> getTranslationIssues() + { + QVersionedPacket<QQmlDebugConnector> packet; + sendMessageToService(createTranslationIssuesRequest(packet)); + QVersionedPacket<QQmlDebugConnector> readPacket(currentReply().at(0)); - packet.clear(); - sendMessageToService(createDisableWatchTextElidesRequest(packet)); + Reply replyType; + QVector<TranslationIssue> translationIssues; + readPacket >> replyType; + readPacket >> translationIssues; - QTRY_VERIFY(gotMessage); - } + return translationIssues; } -private: QByteArray debugServiceMessage(const QByteArray &data) { QByteArray message; @@ -380,10 +253,17 @@ private: } void sendMessageToService(const QByteArray &message) { + clearBuffer(); hooks->qt_qmlDebugSendDataToService( qPrintable(QQmlDebugTranslationServiceImpl::s_key), message.toHex()); } + void clearBuffer() + { + hooks->qt_qmlDebugClearBuffer(); + QCoreApplication::processEvents(); + } + QByteArray currentDebugServiceMessage() { return QByteArray::fromRawData(*hooks->qt_qmlDebugMessageBuffer, *hooks->qt_qmlDebugMessageLength); @@ -424,12 +304,10 @@ private: return "LanguageChanged"; case Reply::StateChanged: return "StateChanged"; - case Reply::MissingTranslations: - return "MissingTranslations"; + case Reply::TranslationIssues: + return "TranslationIssues"; case Reply::TranslatableTextOccurrences: return "TranslatableTextOccurrences"; - case Reply::TextElided: - return "TextElided"; default: Q_ASSERT_X(false, "not implemented", "not implemented"); } @@ -442,7 +320,7 @@ private: QVersionedPacket<QQmlDebugConnector> readPacket(message); readPacket >> replyType; debugString.append(replyTypeToString(replyType)); - if (replyType == Reply::MissingTranslations) { + if (replyType == Reply::TranslationIssues) { QVector<TranslationIssue> translationIssues; readPacket >> translationIssues; QStringList translationIssueStrings; @@ -457,42 +335,10 @@ private: debugString.append(translationIssuesString.arg(QString::number(translationIssues.size()), translationIssueStrings.join("; "))); } - if (replyType == Reply::TextElided) { - TranslationIssue translationIssue; - readPacket >> translationIssue; - debugString.append(QString(" %1 ").arg(translationIssue.toDebugString())); - } } return debugString; } - QString missingRussionTranslationWarningLine42() const - { - const QString fileUrl(testFileUrl(QMLFILE).toString()); - return QString("%1:42:19: QQmlDebugTranslationService: In locale ru ru-RU ru-Cyrl-RU translation is missing.").arg(fileUrl); - } - QString missingFranceTranslationWarningLine47() const - { - const QString fileUrl(testFileUrl(QMLFILE).toString()); - return QString("%1:47:19: QQmlDebugTranslationService: In locale fr fr-FR fr-Latn-FR translation is missing.").arg(fileUrl); - } - QString missingSpainTranslationWarningLine47() const - { - const QString fileUrl(testFileUrl(QMLFILE).toString()); - return QString("%1:47:19: QQmlDebugTranslationService: In locale es es-ES es-Latn-ES translation is missing.").arg(fileUrl); - } - QString missingRussionTranslationWarningLine47() const - { - const QString fileUrl(testFileUrl(QMLFILE).toString()); - return QString("%1:47:19: QQmlDebugTranslationService: In locale ru ru-RU ru-Cyrl-RU translation is missing.").arg(fileUrl); - } - - QString franceElideWarningMessageLine42() const - { - return QString( - "%1:42:19: QQmlDebugTranslationService: In locale fr fr-FR fr-Latn-FR the translated text is eliding." - ).arg(testFileUrl(QMLFILE).toString()); - } QQuickView m_view; QmlState m_currentState; diff --git a/tests/auto/qml/debugger/qqmlenginecontrol/CMakeLists.txt b/tests/auto/qml/debugger/qqmlenginecontrol/CMakeLists.txt index 63eda146ea..faa80f16e4 100644 --- a/tests/auto/qml/debugger/qqmlenginecontrol/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmlenginecontrol/CMakeLists.txt @@ -12,18 +12,17 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlenginecontrol SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h tst_qqmlenginecontrol.cpp INCLUDE_DIRECTORIES - ../../../shared ../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlDebugPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp b/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp index 05abab737e..b209a9e059 100644 --- a/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp +++ b/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp @@ -27,7 +27,7 @@ ****************************************************************************/ #include "debugutil_p.h" -#include "../../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <private/qqmldebugclient_p.h> #include <private/qqmldebugconnection_p.h> @@ -47,7 +47,8 @@ public slots: void blockEngine(int engineId, const QString &name); }; -QQmlEngineBlocker::QQmlEngineBlocker(QQmlEngineControlClient *parent): QObject(parent) +QQmlEngineBlocker::QQmlEngineBlocker(QQmlEngineControlClient *parent) + : QObject(parent) { connect(parent, &QQmlEngineControlClient::engineAboutToBeAdded, this, &QQmlEngineBlocker::blockEngine); @@ -65,6 +66,9 @@ class tst_QQmlEngineControl : public QQmlDebugTest { Q_OBJECT +public: + tst_QQmlEngineControl(); + private: ConnectResult connectTo(const QString &testFile, bool restrictServices); QList<QQmlDebugClient *> createClients() override; @@ -79,6 +83,11 @@ private slots: void stopEngine(); }; +tst_QQmlEngineControl::tst_QQmlEngineControl() + : QQmlDebugTest(QT_QMLTEST_DATADIR) +{ +} + QQmlDebugTest::ConnectResult tst_QQmlEngineControl::connectTo(const QString &file, bool restrictServices) { diff --git a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/CMakeLists.txt b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/CMakeLists.txt index e2553e1abc..f48c9a942b 100644 --- a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/CMakeLists.txt @@ -12,18 +12,17 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlenginedebuginspectorintegration SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h tst_qqmlenginedebuginspectorintegration.cpp INCLUDE_DIRECTORIES - ../../../shared ../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlDebugPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp index 34c6faf4ae..094d3daeb4 100644 --- a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp +++ b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp @@ -27,7 +27,7 @@ ****************************************************************************/ #include "../shared/debugutil_p.h" -#include "../../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <private/qqmldebugconnection_p.h> #include <private/qqmlenginedebugclient_p.h> @@ -45,6 +45,9 @@ class tst_QQmlEngineDebugInspectorIntegration : public QQmlDebugTest { Q_OBJECT +public: + tst_QQmlEngineDebugInspectorIntegration(); + private: ConnectResult init(bool restrictServices); QList<QQmlDebugClient *> createClients() override; @@ -85,6 +88,11 @@ QQmlEngineDebugObjectReference tst_QQmlEngineDebugInspectorIntegration::findRoot return m_engineDebugClient->object(); } +tst_QQmlEngineDebugInspectorIntegration::tst_QQmlEngineDebugInspectorIntegration() + : QQmlDebugTest(QT_QMLTEST_DATADIR) +{ +} + QQmlDebugTest::ConnectResult tst_QQmlEngineDebugInspectorIntegration::init(bool restrictServices) { return QQmlDebugTest::connectTo( diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/CMakeLists.txt b/tests/auto/qml/debugger/qqmlenginedebugservice/CMakeLists.txt index 4c3b449cb4..e632f91548 100644 --- a/tests/auto/qml/debugger/qqmlenginedebugservice/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/CMakeLists.txt @@ -4,22 +4,28 @@ ## tst_qqmlenginedebugservice Test: ##################################################################### +# Collect test data +file(GLOB_RECURSE test_data_glob + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + data/*) +list(APPEND test_data ${test_data_glob}) + qt_internal_add_test(tst_qqmlenginedebugservice SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h tst_qqmlenginedebugservice.cpp DEFINES QT_QML_DEBUG_NO_WARNING INCLUDE_DIRECTORIES - ../../../shared ../shared PUBLIC_LIBRARIES Qt::Gui Qt::QmlDebugPrivate Qt::QmlPrivate Qt::Quick + Qt::QuickTestUtilsPrivate + TESTDATA ${test_data} ) ## Scopes: diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/data/complexItem.qml b/tests/auto/qml/debugger/qqmlenginedebugservice/data/complexItem.qml new file mode 100644 index 0000000000..ae8b681013 --- /dev/null +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/data/complexItem.qml @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import Test 1.0 +Item { + id: root + width: 10; height: 20; scale: blueRect.scale; + Rectangle { id: blueRect; width: 500; height: 600; color: "blue"; } + Text { font.bold: true; color: blueRect.color; } + MouseArea { + onEntered: { console.log('hello') } + } + property variant varObj + property variant varObjList: [] + property variant varObjMap + property variant simpleVar: 10.05 + Component.onCompleted: { + varObj = blueRect; + var list = varObjList; + list[0] = blueRect; + varObjList = list; + var map = new Object; + map.rect = blueRect; + varObjMap = map; + } + NonScriptPropertyElement { + } +} diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/data/customTypes.qml b/tests/auto/qml/debugger/qqmlenginedebugservice/data/customTypes.qml new file mode 100644 index 0000000000..21c0ee84ba --- /dev/null +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/data/customTypes.qml @@ -0,0 +1,31 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import Backend 1.0 +CustomTypes { +} diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/data/emptyItem.qml b/tests/auto/qml/debugger/qqmlenginedebugservice/data/emptyItem.qml new file mode 100644 index 0000000000..9bff34e1e5 --- /dev/null +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/data/emptyItem.qml @@ -0,0 +1,31 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +Item { +} diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/data/itemWithFunctions.qml b/tests/auto/qml/debugger/qqmlenginedebugservice/data/itemWithFunctions.qml new file mode 100644 index 0000000000..ba1617cb37 --- /dev/null +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/data/itemWithFunctions.qml @@ -0,0 +1,34 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +Item { + function myMethodNoArgs() { return 3; } + function myMethod(a) { return a + 9; } + function myMethodIndirect() { myMethod(3); } +} diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/data/jsonTest.qml b/tests/auto/qml/debugger/qqmlenginedebugservice/data/jsonTest.qml new file mode 100644 index 0000000000..53cae7a271 --- /dev/null +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/data/jsonTest.qml @@ -0,0 +1,31 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import JsonTest 1.0 +JsonTest { +} diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/data/rectangleWithTransitions.qml b/tests/auto/qml/debugger/qqmlenginedebugservice/data/rectangleWithTransitions.qml new file mode 100644 index 0000000000..5447c1577a --- /dev/null +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/data/rectangleWithTransitions.qml @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +Rectangle { + id: rootRect + width: 100 + states: [ + State { + name: "state1" + PropertyChanges { + target: rootRect + width: 200 + } + } + ] + transitions: [ + Transition { + from: "*" + to: "state1" + PropertyAnimation { + target: rootRect + property: "width" + duration: 100 + } + } + ] +} diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp index a87a77180f..9d6daa2cd1 100644 --- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp @@ -27,7 +27,7 @@ ****************************************************************************/ #include "debugutil_p.h" -#include "../../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <private/qqmlbinding_p.h> #include <private/qqmlboundsignal_p.h> @@ -119,11 +119,16 @@ private: }; -class tst_QQmlEngineDebugService : public QObject +class tst_QQmlEngineDebugService : public QQmlDataTest { Q_OBJECT public: - tst_QQmlEngineDebugService() : m_conn(nullptr), m_dbg(nullptr), m_engine(nullptr), m_rootItem(nullptr) {} + tst_QQmlEngineDebugService() + : QQmlDataTest(QT_QMLTEST_DATADIR) + , m_conn(nullptr) + , m_dbg(nullptr) + , m_engine(nullptr) + , m_rootItem(nullptr) {} private: QQmlEngineDebugObjectReference findRootObject(int context = 0, @@ -146,7 +151,7 @@ private: QObjectList m_components; private slots: - void initTestCase(); + void initTestCase() override; void cleanupTestCase(); void watch_property(); @@ -327,93 +332,34 @@ void tst_QQmlEngineDebugService::getContexts() void tst_QQmlEngineDebugService::initTestCase() { + QQmlDataTest::initTestCase(); + qmlRegisterType<NonScriptProperty>("Test", 1, 0, "NonScriptPropertyElement"); QTest::ignoreMessage(QtDebugMsg, "QML Debugger: Waiting for connection on port 3768..."); m_engine = new QQmlEngine(this); - QList<QByteArray> qml; - qml << "import QtQuick 2.0\n" - "import Test 1.0\n" - "Item {" - "id: root\n" - "width: 10; height: 20; scale: blueRect.scale;" - "Rectangle { id: blueRect; width: 500; height: 600; color: \"blue\"; }" - "Text { font.bold: true; color: blueRect.color; }" - "MouseArea {" - "onEntered: { console.log('hello') }" - "}" - "property variant varObj\n" - "property variant varObjList: []\n" - "property variant varObjMap\n" - "property variant simpleVar: 10.05\n" - "Component.onCompleted: {\n" - "varObj = blueRect;\n" - "var list = varObjList;\n" - "list[0] = blueRect;\n" - "varObjList = list;\n" - "var map = new Object;\n" - "map.rect = blueRect;\n" - "varObjMap = map;\n" - "}\n" - "NonScriptPropertyElement {\n" - "}\n" - "}"; - - // add second component to test multiple root contexts - qml << "import QtQuick 2.0\n" - "Item {}"; - - // and a third to test methods - qml << "import QtQuick 2.0\n" - "Item {" - "function myMethodNoArgs() { return 3; }\n" - "function myMethod(a) { return a + 9; }\n" - "function myMethodIndirect() { myMethod(3); }\n" - "}"; - - // and a fourth to test states - qml << "import QtQuick 2.0\n" - "Rectangle {\n" - "id:rootRect\n" - "width:100\n" - "states: [\n" - "State {\n" - "name:\"state1\"\n" - "PropertyChanges {\n" - "target:rootRect\n" - "width:200\n" - "}\n" - "}\n" - "]\n" - "transitions: [\n" - "Transition {\n" - "from:\"*\"\n" - "to:\"state1\"\n" - "PropertyAnimation {\n" - "target:rootRect\n" - "property:\"width\"\n" - "duration:100\n" - "}\n" - "}\n" - "]\n" - "}\n" - ; - - // test non-streamable properties qmlRegisterType<CustomTypes>("Backend", 1, 0, "CustomTypes"); - qml << "import Backend 1.0\n" - "CustomTypes {}" - ; - qmlRegisterType<JsonTest>("JsonTest", 1, 0, "JsonTest"); - qml << "import JsonTest 1.0\n" - "JsonTest {}" - ; - for (int i=0; i<qml.count(); i++) { - QQmlComponent component(m_engine); - component.setData(qml[i], QUrl::fromLocalFile("")); + // The contents of these files was previously hardcoded as QList<QByteArray> + // directly in this test, but that fails on Android, because the required + // dependencies are not deployed. When the contents is moved to separate + // files, qmlimportscanner is capable of providing all the necessary + // dependencies. + // Note that the order of the files in this list matters! The test-cases + // expect Qml components to be created is certain order. + constexpr const char *fileNames[] = { + "complexItem.qml", + "emptyItem.qml", + "itemWithFunctions.qml", + "rectangleWithTransitions.qml", + "customTypes.qml", + "jsonTest.qml" + }; + + for (auto file : fileNames) { + QQmlComponent component(m_engine, testFileUrl(file)); QVERIFY(component.isReady()); // fails if bad syntax m_components << qobject_cast<QQuickItem*>(component.create()); } @@ -752,8 +698,8 @@ void tst_QQmlEngineDebugService::queryObject() // check source as defined in main() QQmlEngineDebugFileReference source = obj.source; - QCOMPARE(source.url, QUrl::fromLocalFile("")); - QCOMPARE(source.lineNumber, 3); + QCOMPARE(source.url, testFileUrl("complexItem.qml")); + QCOMPARE(source.lineNumber, 31); // because of license header QCOMPARE(source.columnNumber, 1); // generically test all properties, children and childrens' properties @@ -831,7 +777,7 @@ void tst_QQmlEngineDebugService::queryObjectsForLocation() // check source as defined in main() QQmlEngineDebugFileReference source = obj.source; - QCOMPARE(source.url, QUrl(fileName)); + QCOMPARE(source.url, testFileUrl(fileName)); QCOMPARE(source.lineNumber, lineNumber); QCOMPARE(source.columnNumber, columnNumber); diff --git a/tests/auto/qml/debugger/qqmlinspector/CMakeLists.txt b/tests/auto/qml/debugger/qqmlinspector/CMakeLists.txt index 3303c7d110..4c5ae11084 100644 --- a/tests/auto/qml/debugger/qqmlinspector/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmlinspector/CMakeLists.txt @@ -12,18 +12,17 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlinspector SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h tst_qqmlinspector.cpp INCLUDE_DIRECTORIES - ../../../shared ../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlDebugPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp index 1c72242703..90a10f6dcd 100644 --- a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp +++ b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp @@ -28,7 +28,7 @@ #include "../shared/debugutil_p.h" #include "../shared/qqmldebugprocess_p.h" -#include "../../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <private/qqmldebugconnection_p.h> #include <private/qqmlinspectorclient_p.h> @@ -45,6 +45,9 @@ class tst_QQmlInspector : public QQmlDebugTest { Q_OBJECT +public: + tst_QQmlInspector(); + private: ConnectResult startQmlProcess(const QString &qmlFile, bool restrictMode = true); void checkAnimationSpeed(int targetMillisPerDegree); @@ -61,6 +64,11 @@ private slots: void showAppOnTop(); }; +tst_QQmlInspector::tst_QQmlInspector() + : QQmlDebugTest(QT_QMLTEST_DATADIR) +{ +} + QQmlDebugTest::ConnectResult tst_QQmlInspector::startQmlProcess(const QString &qmlFile, bool restrictServices) { diff --git a/tests/auto/qml/debugger/qqmlpreview/CMakeLists.txt b/tests/auto/qml/debugger/qqmlpreview/CMakeLists.txt index aef78fe28e..2672d0d008 100644 --- a/tests/auto/qml/debugger/qqmlpreview/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmlpreview/CMakeLists.txt @@ -15,18 +15,17 @@ list(APPEND test_data "data/zoom.qml") qt_internal_add_test(tst_qqmlpreview SOURCES ../../../../../src/plugins/qmltooling/qmldbg_preview/qqmlpreviewblacklist.cpp ../../../../../src/plugins/qmltooling/qmldbg_preview/qqmlpreviewblacklist.h - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h tst_qqmlpreview.cpp INCLUDE_DIRECTORIES ../../../../../src/plugins/qmltooling/qmldbg_preview - ../../../shared ../shared PUBLIC_LIBRARIES Qt::Gui Qt::Qml Qt::QmlDebugPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp index 8d24c9fc52..cc48e43c08 100644 --- a/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp +++ b/tests/auto/qml/debugger/qqmlpreview/tst_qqmlpreview.cpp @@ -45,6 +45,9 @@ class tst_QQmlPreview : public QQmlDebugTest { Q_OBJECT +public: + tst_QQmlPreview(); + private: ConnectResult startQmlProcess(const QString &qmlFile); void serveRequest(const QString &path); @@ -71,6 +74,11 @@ private slots: void fps(); }; +tst_QQmlPreview::tst_QQmlPreview() + : QQmlDebugTest(QT_QMLTEST_DATADIR) +{ +} + QQmlDebugTest::ConnectResult tst_QQmlPreview::startQmlProcess(const QString &qmlFile) { return QQmlDebugTest::connectTo(QLibraryInfo::path(QLibraryInfo::BinariesPath) + "/qml", diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/CMakeLists.txt b/tests/auto/qml/debugger/qqmlprofilerservice/CMakeLists.txt index 394e4aa08d..3d57619bbb 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/CMakeLists.txt +++ b/tests/auto/qml/debugger/qqmlprofilerservice/CMakeLists.txt @@ -12,17 +12,16 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlprofilerservice SOURCES - ../../../shared/util.cpp ../../../shared/util.h ../shared/debugutil.cpp ../shared/debugutil_p.h ../shared/qqmldebugprocess.cpp ../shared/qqmldebugprocess_p.h tst_qqmlprofilerservice.cpp INCLUDE_DIRECTORIES - ../../../shared ../shared PUBLIC_LIBRARIES Qt::Gui Qt::GuiPrivate Qt::QmlDebugPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index 2b564e48ad..54ba3f2a27 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -28,7 +28,7 @@ #include "debugutil_p.h" #include "qqmldebugprocess_p.h" -#include "../../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <private/qqmlprofilerclient_p.h> #include <private/qqmldebugconnection_p.h> @@ -45,8 +45,8 @@ class QQmlProfilerTestClient : public QQmlProfilerEventReceiver Q_OBJECT public: - QQmlProfilerTestClient(QQmlDebugConnection *connection) : - client(new QQmlProfilerClient(connection, this)) + QQmlProfilerTestClient(QQmlDebugConnection *connection) + : client(new QQmlProfilerClient(connection, this)) { connect(client.data(), &QQmlProfilerClient::traceStarted, this, &QQmlProfilerTestClient::startTrace); @@ -180,6 +180,9 @@ class tst_QQmlProfilerService : public QQmlDebugTest { Q_OBJECT +public: + tst_QQmlProfilerService(); + private: enum MessageListType { MessageListQML, @@ -246,6 +249,11 @@ private: #define VERIFY(type, position, expected, checks, numbers) \ QVERIFY(verify(type, position, expected, checks, numbers)) +tst_QQmlProfilerService::tst_QQmlProfilerService() + : QQmlDebugTest(QT_QMLTEST_DATADIR) +{ +} + QQmlDebugTest::ConnectResult tst_QQmlProfilerService::connectTo( bool block, const QString &file, bool recordFromStart, uint flushInterval, bool restrictServices, const QString &executable) diff --git a/tests/auto/qml/debugger/qv4debugger/CMakeLists.txt b/tests/auto/qml/debugger/qv4debugger/CMakeLists.txt index f106208737..92565f55c1 100644 --- a/tests/auto/qml/debugger/qv4debugger/CMakeLists.txt +++ b/tests/auto/qml/debugger/qv4debugger/CMakeLists.txt @@ -4,6 +4,24 @@ ## tst_qv4debugger Test: ##################################################################### +# Collect test data +file(GLOB_RECURSE test_data_glob + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + data/*) +list(APPEND test_data ${test_data_glob}) + +qt_add_library(testCppTypes STATIC) +qt_autogen_tools_initial_setup(testCppTypes) +target_link_libraries(testCppTypes PRIVATE Qt::Qml Qt::QmlPrivate Qt::Quick) + +qt6_add_qml_module(testCppTypes + VERSION 1.0 + URI TestTypes + SOURCES + commontypes.h +) +qt_autogen_tools_initial_setup(testCppTypesplugin) + qt_internal_add_test(tst_qv4debugger SOURCES ../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp ../../../../../src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -18,7 +36,20 @@ qt_internal_add_test(tst_qv4debugger Qt::GuiPrivate Qt::Network Qt::QmlPrivate + Qt::QuickTestUtilsPrivate + testCppTypesplugin + TESTDATA ${test_data} ) ## Scopes: ##################################################################### + +qt_internal_extend_target(tst_qv4debugger CONDITION ANDROID OR IOS + DEFINES + QT_QMLTEST_DATADIR=\\\":/data\\\" + ) + +qt_internal_extend_target(tst_qv4debugger CONDITION NOT ANDROID AND NOT IOS + DEFINES + QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\" + ) diff --git a/tests/auto/qml/debugger/qv4debugger/commontypes.h b/tests/auto/qml/debugger/qv4debugger/commontypes.h new file mode 100644 index 0000000000..01b2125ae3 --- /dev/null +++ b/tests/auto/qml/debugger/qv4debugger/commontypes.h @@ -0,0 +1,20 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef COMMONTYPES_H +#define COMMONTYPES_H + +#include <QtQuick/qquickitem.h> +#include <QtQml/qqmlregistration.h> +#include <QtQml/private/qv4engine_p.h> + +class MyType : public QQuickItem +{ + Q_OBJECT + QML_ELEMENT +public: + MyType(QQuickItem *parent = nullptr) : QQuickItem(parent) {} + Q_INVOKABLE void name(QQmlV4Function*) const {} +}; + +#endif // COMMONTYPES_H diff --git a/tests/auto/qml/debugger/qv4debugger/data/conditionalBreakPointInQml.qml b/tests/auto/qml/debugger/qv4debugger/data/conditionalBreakPointInQml.qml new file mode 100644 index 0000000000..ceb4edbe7a --- /dev/null +++ b/tests/auto/qml/debugger/qv4debugger/data/conditionalBreakPointInQml.qml @@ -0,0 +1,9 @@ +import QtQml 2.0 +QtObject { + id: root + property int foo: 42 + property bool success: false + Component.onCompleted: { + success = true; // break here + } +} diff --git a/tests/auto/qml/debugger/qv4debugger/data/qtbug_107607.qml b/tests/auto/qml/debugger/qv4debugger/data/qtbug_107607.qml new file mode 100644 index 0000000000..a7758de8a8 --- /dev/null +++ b/tests/auto/qml/debugger/qv4debugger/data/qtbug_107607.qml @@ -0,0 +1,10 @@ +import QtQuick +import TestTypes +MyType { + objectName: "patron" + Item { + Component.onCompleted: { + console.log("Hallo Welt"); + } + } +}
\ No newline at end of file diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index 610665146b..b9b2fd6b69 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -25,6 +25,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <QtTest/QtTest> #include "qv4datacollector.h" @@ -40,10 +41,13 @@ #include <private/qv4string_p.h> #include <private/qqmlbuiltinfunctions_p.h> #include <private/qqmldebugservice_p.h> +#include <QtQml/qqmlextensionplugin.h> using namespace QV4; using namespace QV4::Debugging; +Q_IMPORT_QML_PLUGIN(TestTypesPlugin); + typedef QV4::ReturnedValue (*InjectedFunction)(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int); Q_DECLARE_METATYPE(InjectedFunction) @@ -200,7 +204,15 @@ public slots: ExpressionEvalJob job(debugger->engine(), request.frameNr, request.context, request.expression, &collector); debugger->runInEngine(&job); - m_expressionResults << job.returnValue(); + const QJsonObject& result = job.returnValue(); + m_expressionResults << result; + + if (request.shouldLookup) { + QJsonArray handles {result.value("handle").toInt()}; + ValueLookupJob job(handles, &collector); + debugger->runInEngine(&job); + m_lookupResults << job.returnValue(); + } } if (m_captureContextInfo) @@ -273,10 +285,14 @@ public: QString expression; int frameNr; int context; + bool shouldLookup = false; }; + + QVector<ExpressionRequest> m_expressionRequests; QV4Debugger::Speed m_resumeSpeed; QList<QJsonObject> m_expressionResults; + QList<QJsonObject> m_lookupResults; QV4Debugger *m_debugger; // Utility methods: @@ -289,10 +305,13 @@ public: } }; -class tst_qv4debugger : public QObject +class tst_qv4debugger : public QQmlDataTest { Q_OBJECT +public: + tst_qv4debugger(); + private slots: void init(); void cleanup(); @@ -327,7 +346,7 @@ private slots: void readThis(); void signalParameters(); - + void debuggerNoCrash(); private: QV4Debugger *debugger() const { @@ -489,7 +508,7 @@ void tst_qv4debugger::conditionalBreakPoint() QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1); const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0); - QCOMPARE(frame0.size(), 3); + QCOMPARE(frame0.size(), 2); QVERIFY(frame0.contains("i")); QCOMPARE(frame0.value("i").toInt(), 11); } @@ -507,24 +526,17 @@ void tst_qv4debugger::conditionalBreakPointInQml() debuggerAgent->addDebugger(v4Debugger); debuggerAgent->moveToThread(debugThread.data()); - QQmlComponent component(&engine); - component.setData("import QtQml 2.0\n" - "QtObject {\n" - " id: root\n" - " property int foo: 42\n" - " property bool success: false\n" - " Component.onCompleted: {\n" - " success = true;\n" // breakpoint here - " }\n" - "}\n", QUrl("test.qml")); + const QString qmlFileName("conditionalBreakPointInQml.qml"); + const QString qmlFilePath(testFile(qmlFileName)); + QQmlComponent component(&engine, qmlFilePath); - v4Debugger->addBreakPoint("test.qml", 7, "root.foo == 42"); + v4Debugger->addBreakPoint(qmlFileName, 7, "root.foo == 42"); QScopedPointer<QObject> obj(component.create()); QCOMPARE(obj->property("success").toBool(), true); QCOMPARE(debuggerAgent->m_statesWhenPaused.count(), 1); - QCOMPARE(debuggerAgent->m_statesWhenPaused.at(0).fileName, QStringLiteral("test.qml")); + QCOMPARE(debuggerAgent->m_statesWhenPaused.at(0).fileName, qmlFileName); QCOMPARE(debuggerAgent->m_statesWhenPaused.at(0).lineNumber, 7); debugThread->quit(); @@ -545,7 +557,7 @@ void tst_qv4debugger::readArguments() QVERIFY(m_debuggerAgent->m_wasPaused); QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1); const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0); - QCOMPARE(frame0.size(), 5); + QCOMPARE(frame0.size(), 4); QVERIFY(frame0.contains(QStringLiteral("a"))); QCOMPARE(frame0.type(QStringLiteral("a")), QStringLiteral("number")); QCOMPARE(frame0.value(QStringLiteral("a")).toDouble(), 1.0); @@ -568,7 +580,7 @@ void tst_qv4debugger::readComplicatedArguments() QVERIFY(m_debuggerAgent->m_wasPaused); QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1); const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0); - QCOMPARE(frame0.size(), 2); + QCOMPARE(frame0.size(), 1); QVERIFY(frame0.contains(QStringLiteral("a"))); QCOMPARE(frame0.type(QStringLiteral("a")), QStringLiteral("number")); QCOMPARE(frame0.value(QStringLiteral("a")).toInt(), 12); @@ -591,7 +603,7 @@ void tst_qv4debugger::readLocals() QVERIFY(m_debuggerAgent->m_wasPaused); QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1); const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0); - QCOMPARE(frame0.size(), 7); // locals and parameters + QCOMPARE(frame0.size(), 6); // locals and parameters QVERIFY(frame0.contains("c")); QCOMPARE(frame0.type("c"), QStringLiteral("number")); QCOMPARE(frame0.value("c").toDouble(), 3.0); @@ -619,7 +631,7 @@ void tst_qv4debugger::readObject() QVERIFY(m_debuggerAgent->m_wasPaused); QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1); const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0); - QCOMPARE(frame0.size(), 3); + QCOMPARE(frame0.size(), 2); QVERIFY(frame0.contains("b")); QCOMPARE(frame0.type("b"), QStringLiteral("object")); QJsonObject b = frame0.rawValue("b"); @@ -680,7 +692,7 @@ void tst_qv4debugger::readContextInAllFrames() for (int i = 0; i < 12; ++i) { const TestAgent::NamedRefs &scope = m_debuggerAgent->m_capturedScope.at(i); - QCOMPARE(scope.size(), 3); + QCOMPARE(scope.size(), 2); QVERIFY(scope.contains("n")); QCOMPARE(scope.type("n"), QStringLiteral("number")); QCOMPARE(scope.value("n").toDouble(), i + 1.0); @@ -944,6 +956,44 @@ void tst_qv4debugger::signalParameters() QCOMPARE(obj->property("resultCallbackExternal").toString(), QLatin1String("unset")); } +void tst_qv4debugger::debuggerNoCrash() +{ + QQmlEngine engine; + QV4::ExecutionEngine *v4 = engine.handle(); + QPointer<QV4Debugger> v4Debugger = new QV4Debugger(v4); + v4->setDebugger(v4Debugger.data()); + + QScopedPointer<QThread> debugThread(new QThread); + debugThread->start(); + QScopedPointer<TestAgent> debuggerAgent(new TestAgent(v4)); + debuggerAgent->addDebugger(v4Debugger); + debuggerAgent->moveToThread(debugThread.data()); + + const QString qmlFileName("qtbug_107607.qml"); + const QString qmlFilePath(testFile(qmlFileName)); + QQmlComponent component(&engine, qmlFilePath); + + TestAgent::ExpressionRequest request; + request.expression = "this.parent"; + request.frameNr = 0; + request.context = -1; + request.shouldLookup = true; + debuggerAgent->m_expressionRequests << request; + v4Debugger->addBreakPoint(qmlFileName, 7); + + QScopedPointer<QObject> obj(component.create()); + + QVERIFY(debuggerAgent->m_lookupResults.size() > 0); + const QJsonObject result = debuggerAgent->m_lookupResults[0]; + const QJsonArray properties = result["0"].toObject().value("properties").toArray(); + QCOMPARE(properties[0].toObject().value("value").toString(), QStringLiteral("patron")); + + debugThread->quit(); + debugThread->wait(); +} + +tst_qv4debugger::tst_qv4debugger() : QQmlDataTest(QT_QMLTEST_DATADIR) { } + QTEST_MAIN(tst_qv4debugger) #include "tst_qv4debugger.moc" diff --git a/tests/auto/qml/debugger/shared/debugutil.cpp b/tests/auto/qml/debugger/shared/debugutil.cpp index 3787f34bc2..4598e288c7 100644 --- a/tests/auto/qml/debugger/shared/debugutil.cpp +++ b/tests/auto/qml/debugger/shared/debugutil.cpp @@ -34,6 +34,11 @@ #include <QtCore/qeventloop.h> #include <QtCore/qtimer.h> +QQmlDebugTest::QQmlDebugTest(const char *qmlTestDataDir) + : QQmlDataTest(qmlTestDataDir) +{ +} + bool QQmlDebugTest::waitForSignal(QObject *receiver, const char *member, int timeout) { QEventLoop loop; QTimer timer; diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h index ad24eaa7f8..e19f59d3f2 100644 --- a/tests/auto/qml/debugger/shared/debugutil_p.h +++ b/tests/auto/qml/debugger/shared/debugutil_p.h @@ -40,7 +40,7 @@ // We mean it. // -#include <../../../shared/util.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <private/qqmldebugclient_p.h> class QQmlDebugProcess; @@ -48,6 +48,9 @@ class QQmlDebugTest : public QQmlDataTest { Q_OBJECT public: + QQmlDebugTest(const char *qmlTestDataDir); + +public: static bool waitForSignal(QObject *receiver, const char *member, int timeout = 5000); static QList<QQmlDebugClient *> createOtherClients(QQmlDebugConnection *connection); static QString clientStateString(const QQmlDebugClient *client); diff --git a/tests/auto/qml/ecmascripttests/CMakeLists.txt b/tests/auto/qml/ecmascripttests/CMakeLists.txt index 78e1c97e91..078881c41a 100644 --- a/tests/auto/qml/ecmascripttests/CMakeLists.txt +++ b/tests/auto/qml/ecmascripttests/CMakeLists.txt @@ -13,4 +13,6 @@ qt_internal_add_test(tst_ecmascripttests ) set_property(TEST tst_ecmascripttests APPEND PROPERTY ENVIRONMENT "QTEST_FUNCTION_TIMEOUT=900000") -add_subdirectory(qjstest) +if(NOT CMAKE_CROSSCOMPILING) + add_subdirectory(qjstest) +endif() diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index 6b743ba433..82d80f7f03 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -600,7 +600,6 @@ language/statements/class/definition/methods-gen-yield-as-literal-property-name. language/statements/class/definition/methods-gen-yield-as-property-name.js fails language/statements/class/definition/methods-named-eval-arguments.js fails language/statements/class/definition/prototype-property.js fails -language/statements/class/definition/setters-prop-desc.js fails language/statements/class/definition/setters-restricted-ids.js fails language/statements/class/definition/this-access-restriction-2.js fails language/statements/class/definition/this-access-restriction.js fails diff --git a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp index 24633d9c6d..9037ed0c92 100644 --- a/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp +++ b/tests/auto/qml/ecmascripttests/qjstest/test262runner.cpp @@ -393,9 +393,7 @@ void Test262Runner::loadTestExpectations() return; } - int line = 0; while (!file.atEnd()) { - ++line; QByteArray line = file.readLine().trimmed(); if (line.startsWith('#') || line.isEmpty()) continue; @@ -440,9 +438,7 @@ void Test262Runner::updateTestExpectations() QTemporaryFile updatedExpectations; updatedExpectations.open(); - int line = 0; while (!file.atEnd()) { - ++line; QByteArray originalLine = file.readLine(); QByteArray line = originalLine.trimmed(); if (line.startsWith('#') || line.isEmpty()) { diff --git a/tests/auto/qml/parserstress/CMakeLists.txt b/tests/auto/qml/parserstress/CMakeLists.txt index 2d2f3df4c3..4505dab1da 100644 --- a/tests/auto/qml/parserstress/CMakeLists.txt +++ b/tests/auto/qml/parserstress/CMakeLists.txt @@ -18,8 +18,12 @@ qt_internal_add_test(tst_parserstress Qt::Gui Qt::GuiPrivate Qt::QmlPrivate - TESTDATA ${test_data} + TESTDATA ${test_data} "dummy_imports.qml" ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_parserstress) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/parserstress/dummy_imports.qml b/tests/auto/qml/parserstress/dummy_imports.qml index b9a196e188..63d33cbea6 100644 --- a/tests/auto/qml/parserstress/dummy_imports.qml +++ b/tests/auto/qml/parserstress/dummy_imports.qml @@ -1,8 +1,7 @@ // This file exists for the sole purpose for qmlimportscanner to find // which modules it needs to extract for deployment. -// Otherwise, it fails to find the imports that are expressed in C++ -// code in tst_parserstress.cpp +// Otherwise, it fails to find the imports that are expressed in C++. -import QtQuick 2.0 +import QtQuick -QtObject { } // This is needed in order to keep importscanner happy +QtObject { } diff --git a/tests/auto/qml/qjsengine/CMakeLists.txt b/tests/auto/qml/qjsengine/CMakeLists.txt index 3488a73a25..86efc2c0c2 100644 --- a/tests/auto/qml/qjsengine/CMakeLists.txt +++ b/tests/auto/qml/qjsengine/CMakeLists.txt @@ -28,7 +28,7 @@ qt_internal_add_test(tst_qjsengine Qt::Widgets LIBRARIES # special case Threads::Threads # special case - TESTDATA ${test_data} + TESTDATA ${test_data} "dummy_imports.qml" ) # Resources: @@ -62,6 +62,10 @@ qt_internal_add_resource(tst_qjsengine "qmake_immediate" ${qmake_immediate_resource_files} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qjsengine) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qjsengine/dummy_imports.qml b/tests/auto/qml/qjsengine/dummy_imports.qml index 8d86f3583b..afe2b33adf 100644 --- a/tests/auto/qml/qjsengine/dummy_imports.qml +++ b/tests/auto/qml/qjsengine/dummy_imports.qml @@ -1,8 +1,7 @@ // This file exists for the sole purpose for qmlimportscanner to find // which modules it needs to extract for deployment. -// Otherwise, it fails to find the imports that are expressed in C++ -// code in tst_parserstress.cpp +// Otherwise, it fails to find the imports that are expressed in C++. -import QtQml 2.0 +import QtQml -QtObject { } // This is needed in order to keep importscanner happy +QtObject { } diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 1cc48bd73b..a5e8713700 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -105,6 +105,7 @@ private slots: void valueConversion_RegularExpression(); void castWithMultipleInheritance(); void collectGarbage(); + void collectGarbageNestedWrappersTwoEngines(); void gcWithNestedDataStructure(); void stacktrace(); void numberParsing_data(); @@ -264,11 +265,13 @@ private slots: void triggerBackwardJumpWithDestructuring(); void arrayConcatOnSparseArray(); + void concatAfterUnshift(); void sortSparseArray(); void compileBrokenRegexp(); void sortNonStringArray(); void iterateInvalidProxy(); void applyOnHugeArray(); + void reflectApplyOnHugeArray(); void tostringRecursionCheck(); void arrayIncludesWithLargeArray(); @@ -278,6 +281,8 @@ private slots: void uiLanguage(); void urlObject(); + void thisInConstructor(); + void forOfAndGc(); public: Q_INVOKABLE QJSValue throwingCppMethod1(); @@ -855,7 +860,11 @@ void tst_QJSEngine::newQObjectRace() { void run() override { - for (int i=0;i<1000;++i) + int newObjectCount = 1000; +#if defined(Q_OS_QNX) + newObjectCount = 256; +#endif + for (int i=0;i<newObjectCount;++i) { QJSEngine e; auto obj = e.newQObject(new QObject); @@ -1841,6 +1850,44 @@ void tst_QJSEngine::collectGarbage() QVERIFY(ptr.isNull()); } +class TestObjectContainer : public QObject +{ + Q_OBJECT + Q_PROPERTY(QObject *dummy MEMBER m_dummy CONSTANT) + +public: + TestObjectContainer() : m_dummy(new QObject(this)) {} + +private: + QObject *m_dummy; +}; + +void tst_QJSEngine::collectGarbageNestedWrappersTwoEngines() +{ + QJSEngine engine1; + QJSEngine engine2; + + TestObjectContainer container; + QQmlEngine::setObjectOwnership(&container, QQmlEngine::CppOwnership); + + engine1.globalObject().setProperty("foobar", engine1.newQObject(&container)); + engine2.globalObject().setProperty("foobar", engine2.newQObject(&container)); + + engine1.evaluate("foobar.dummy.baz = 42"); + engine2.evaluate("foobar.dummy.baz = 43"); + + QCOMPARE(engine1.evaluate("foobar.dummy.baz").toInt(), 42); + QCOMPARE(engine2.evaluate("foobar.dummy.baz").toInt(), 43); + + engine1.collectGarbage(); + engine2.collectGarbage(); + + // The GC should not collect dummy object wrappers neither in engine1 nor engine2, we + // verify that by checking whether the baz property still has its previous value. + QCOMPARE(engine1.evaluate("foobar.dummy.baz").toInt(), 42); + QCOMPARE(engine2.evaluate("foobar.dummy.baz").toInt(), 43); +} + void tst_QJSEngine::gcWithNestedDataStructure() { // The GC must be able to traverse deeply nested objects, otherwise this @@ -5148,6 +5195,23 @@ void tst_QJSEngine::arrayConcatOnSparseArray() QVERIFY(value.property(i).isUndefined()); } +void tst_QJSEngine::concatAfterUnshift() +{ + QJSEngine engine; + const auto value = engine.evaluate(uR"( + (function() { + let test = ['val2'] + test.unshift('val1') + test = test.concat([]) + return test + })() + )"_qs); + QVERIFY2(!value.isError(), qPrintable(value.toString())); + QVERIFY(value.isArray()); + QCOMPARE(value.property(0).toString(), u"val1"_qs); + QCOMPARE(value.property(1).toString(), u"val2"_qs); +} + void tst_QJSEngine::sortSparseArray() { QJSEngine engine; @@ -5264,12 +5328,28 @@ void tst_QJSEngine::applyOnHugeArray() QCOMPARE(value.toString(), "RangeError: Array too large for apply()."); } + +void tst_QJSEngine::reflectApplyOnHugeArray() +{ + QQmlEngine engine; + const QJSValue value = engine.evaluate(R"( +(function(){ +const v1 = []; +const v3 = []; +v3.length = 3900000000; +Reflect.apply(v1.reverse,v1,v3); +})() + )"); + QVERIFY(value.isError()); + QCOMPARE(value.toString(), QLatin1String("RangeError: Invalid array length.")); +} + void tst_QJSEngine::typedArraySet() { QJSEngine engine; const auto value = engine.evaluate( "(function() {" - " var length = 0xffffffe;" + " var length = 0xfffffe0;" " var offset = 0xfffffff0;" " var e1;" " var e2;" @@ -5418,6 +5498,97 @@ void tst_QJSEngine::urlObject() QCOMPARE(result2, url); } +void tst_QJSEngine::thisInConstructor() +{ + QJSEngine engine; + const QJSValue result = engine.evaluate(R"((function() { + let a = undefined; + class Bugtest { + constructor() { + (() => { + if (true) { + a = this; + } + })(); + } + }; + new Bugtest(); + return a; + })())"); + QVERIFY(!result.isUndefined()); + QVERIFY(result.isObject()); +} + +void tst_QJSEngine::forOfAndGc() +{ + // We want to guard against the iterator of a for..of loop leaving the result unprotected from + // garbage collection. It should be possible to construct a pure JS test case, but due to the + // vaguaries of garbage collection it's hard to reliably trigger the crash. This test is the + // best I could come up with. + + QQmlEngine engine; + QQmlComponent c(&engine); + c.setData(R"( + import QtQml + + QtObject { + id: counter + property int count: 0 + + property DelegateModel model: DelegateModel { + id: filesModel + + model: ListModel { + Component.onCompleted: { + for (let idx = 0; idx < 50; idx++) + append({"i" : idx}) + } + } + + groups: [ + DelegateModelGroup { + name: "selected" + } + ] + + function getSelected() { + for (let i = 0; i < items.count; ++i) { + var item = items.get(i) + for (let el of item.groups) { + if (el === "selected") + ++counter.count + } + } + } + + property bool bSelect: true + function selectAll() { + for (let i = 0; i < items.count; ++i) { + if (bSelect && !items.get(i).inSelected) + items.addGroups(i, 1, ["selected"]) + else + items.removeGroups(i, 1, ["selected"]) + getSelected() + } + bSelect = !bSelect + } + } + + property Timer timer: Timer { + running: true + interval: 1 + repeat: true + onTriggered: filesModel.selectAll() + } + } + )", QUrl()); + + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + + QTRY_VERIFY(o->property("count").toInt() > 32768); +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" diff --git a/tests/auto/qml/qjsmanagedvalue/CMakeLists.txt b/tests/auto/qml/qjsmanagedvalue/CMakeLists.txt index 3e466d8e2e..2449b9a320 100644 --- a/tests/auto/qml/qjsmanagedvalue/CMakeLists.txt +++ b/tests/auto/qml/qjsmanagedvalue/CMakeLists.txt @@ -10,7 +10,12 @@ qt_internal_add_test(tst_qjsmanagedvalue PUBLIC_LIBRARIES Qt::Qml Qt::QmlPrivate + TESTDATA "dummy_imports.qml" ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qjsmanagedvalue) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qjsmanagedvalue/dummy_imports.qml b/tests/auto/qml/qjsmanagedvalue/dummy_imports.qml new file mode 100644 index 0000000000..afe2b33adf --- /dev/null +++ b/tests/auto/qml/qjsmanagedvalue/dummy_imports.qml @@ -0,0 +1,7 @@ +// This file exists for the sole purpose for qmlimportscanner to find +// which modules it needs to extract for deployment. +// Otherwise, it fails to find the imports that are expressed in C++. + +import QtQml + +QtObject { } diff --git a/tests/auto/qml/qjsonbinding/CMakeLists.txt b/tests/auto/qml/qjsonbinding/CMakeLists.txt index 1704e4e790..b85fd7b99c 100644 --- a/tests/auto/qml/qjsonbinding/CMakeLists.txt +++ b/tests/auto/qml/qjsonbinding/CMakeLists.txt @@ -12,14 +12,12 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qjsonbinding SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qjsonbinding.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::GuiPrivate Qt::Qml + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qjsonbinding/tst_qjsonbinding.cpp b/tests/auto/qml/qjsonbinding/tst_qjsonbinding.cpp index 05e1ce8b6b..4c12f6d44c 100644 --- a/tests/auto/qml/qjsonbinding/tst_qjsonbinding.cpp +++ b/tests/auto/qml/qjsonbinding/tst_qjsonbinding.cpp @@ -27,7 +27,7 @@ ****************************************************************************/ #include <QtTest/QtTest> #include <QtQml/QtQml> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> Q_DECLARE_METATYPE(QJsonValue::Type) @@ -55,7 +55,7 @@ class tst_qjsonbinding : public QQmlDataTest { Q_OBJECT public: - tst_qjsonbinding() {} + tst_qjsonbinding() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void cppJsConversion_data(); @@ -77,6 +77,9 @@ private slots: void writeProperty_javascriptExpression_data(); void writeProperty_javascriptExpression(); + void cyclicStringify(); + void recursiveStringify(); + private: QByteArray readAsUtf8(const QString &fileName); static QJsonValue valueFromJson(const QByteArray &json); @@ -514,6 +517,43 @@ void tst_qjsonbinding::writeProperty_javascriptExpression() QCOMPARE(ret.toString(), expectedJson); } +void tst_qjsonbinding::cyclicStringify() +{ + QJSEngine e; + const QString program = QStringLiteral(R"( + var a = {}; + a.a = a; + JSON.stringify(a); + )"); + + QJSValue result = e.evaluate(program); + QVERIFY(result.isError()); + QCOMPARE(result.errorType(), QJSValue::TypeError); + QVERIFY(result.toString().contains(QLatin1String("Cannot convert circular structure to JSON"))); +} + +void tst_qjsonbinding::recursiveStringify() +{ + QJSEngine e; + const QString program = QStringLiteral(R"( + function create() { + var a = {} + Object.defineProperty(a, "a", { + enumerable: true, + get: function() { return create(); } + }); + return a; + } + + JSON.stringify(create()); + )"); + + QJSValue result = e.evaluate(program); + QVERIFY(result.isError()); + QCOMPARE(result.errorType(), QJSValue::RangeError); + QVERIFY(result.toString().contains(QLatin1String("Maximum call stack size exceeded"))); +} + QTEST_MAIN(tst_qjsonbinding) #include "tst_qjsonbinding.moc" diff --git a/tests/auto/qml/qjsvalue/CMakeLists.txt b/tests/auto/qml/qjsvalue/CMakeLists.txt index bb00f3221a..b8ee79713c 100644 --- a/tests/auto/qml/qjsvalue/CMakeLists.txt +++ b/tests/auto/qml/qjsvalue/CMakeLists.txt @@ -22,7 +22,12 @@ qt_internal_add_test(tst_qjsvalue Qt::Widgets LIBRARIES # special case Threads::Threads # special case + TESTDATA "dummy_imports.qml" ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qjsvalue) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qjsvalue/dummy_imports.qml b/tests/auto/qml/qjsvalue/dummy_imports.qml new file mode 100644 index 0000000000..afe2b33adf --- /dev/null +++ b/tests/auto/qml/qjsvalue/dummy_imports.qml @@ -0,0 +1,7 @@ +// This file exists for the sole purpose for qmlimportscanner to find +// which modules it needs to extract for deployment. +// Otherwise, it fails to find the imports that are expressed in C++. + +import QtQml + +QtObject { } diff --git a/tests/auto/qml/qmlbasicapp/BasicExtension/CMakeLists.txt b/tests/auto/qml/qmlbasicapp/BasicExtension/CMakeLists.txt index 6aad55abdc..a08c71a294 100644 --- a/tests/auto/qml/qmlbasicapp/BasicExtension/CMakeLists.txt +++ b/tests/auto/qml/qmlbasicapp/BasicExtension/CMakeLists.txt @@ -1,7 +1,7 @@ qt_add_library(additional_qml_module STATIC) qt_autogen_tools_initial_setup(additional_qml_module) -qt_add_plugin(additional_qml_module_plugin STATIC TYPE qml_plugin CLASS_NAME BasicExtension) +qt_add_plugin(additional_qml_module_plugin STATIC PLUGIN_TYPE qml_plugin CLASS_NAME BasicExtension) qt_autogen_tools_initial_setup(additional_qml_module_plugin) qt6_add_qml_module(additional_qml_module @@ -11,4 +11,9 @@ qt6_add_qml_module(additional_qml_module URI "BasicExtension" QML_FILES Extension.qml + More.ui.qml + Less.js + ESModule.mjs + lowerCase.js + lowerCaseModule.mjs ) diff --git a/tests/auto/qml/qmlbasicapp/BasicExtension/ESModule.mjs b/tests/auto/qml/qmlbasicapp/BasicExtension/ESModule.mjs new file mode 100644 index 0000000000..e1424dc501 --- /dev/null +++ b/tests/auto/qml/qmlbasicapp/BasicExtension/ESModule.mjs @@ -0,0 +1 @@ +export function eee() { return "eee" } diff --git a/tests/auto/qml/qmlbasicapp/BasicExtension/Less.js b/tests/auto/qml/qmlbasicapp/BasicExtension/Less.js new file mode 100644 index 0000000000..a808d7be27 --- /dev/null +++ b/tests/auto/qml/qmlbasicapp/BasicExtension/Less.js @@ -0,0 +1 @@ +function bar() { return "bar" } diff --git a/tests/auto/qml/qmlbasicapp/BasicExtension/More.ui.qml b/tests/auto/qml/qmlbasicapp/BasicExtension/More.ui.qml new file mode 100644 index 0000000000..014d794229 --- /dev/null +++ b/tests/auto/qml/qmlbasicapp/BasicExtension/More.ui.qml @@ -0,0 +1,3 @@ +import QtQml + +QtObject { objectName: "ui.qml" } diff --git a/tests/auto/qml/qmlbasicapp/BasicExtension/lowerCase.js b/tests/auto/qml/qmlbasicapp/BasicExtension/lowerCase.js new file mode 100644 index 0000000000..9d90c9c6f1 --- /dev/null +++ b/tests/auto/qml/qmlbasicapp/BasicExtension/lowerCase.js @@ -0,0 +1 @@ +function a() { return "a" } diff --git a/tests/auto/qml/qmlbasicapp/BasicExtension/lowerCaseModule.mjs b/tests/auto/qml/qmlbasicapp/BasicExtension/lowerCaseModule.mjs new file mode 100644 index 0000000000..f35813109c --- /dev/null +++ b/tests/auto/qml/qmlbasicapp/BasicExtension/lowerCaseModule.mjs @@ -0,0 +1 @@ +export function fff() { return "fff" } diff --git a/tests/auto/qml/qmlbasicapp/CMakeLists.txt b/tests/auto/qml/qmlbasicapp/CMakeLists.txt index a52cf72923..269cc35980 100644 --- a/tests/auto/qml/qmlbasicapp/CMakeLists.txt +++ b/tests/auto/qml/qmlbasicapp/CMakeLists.txt @@ -9,13 +9,22 @@ qt_internal_add_test(tst_qmlbasicapp qt6_add_qml_module(tst_qmlbasicapp VERSION 1.0 URI "BasicApp" - NO_CREATE_PLUGIN_TARGET QML_FILES main.qml ) add_subdirectory(BasicExtension) -target_link_libraries(tst_qmlbasicapp PRIVATE additional_qml_module additional_qml_module_plugin) - add_subdirectory(TimeExample) -add_dependencies(tst_qmlbasicapp qmlqtimeexample qmlqtimeexampleplugin) + +if(QT6_IS_SHARED_LIBS_BUILD) + # Plugins are static, but qt6_import_qml_plugins() can't be used because + # it does nothing for shared builds. Import and link the plugins manually. + target_sources(tst_qmlbasicapp PRIVATE manual_imports.cpp) + target_link_libraries(tst_qmlbasicapp PRIVATE + additional_qml_module_plugin + qmlqtimeexampleplugin + ) +else() + # For fully static builds, let qmlimportscanner take care of everything + qt6_import_qml_plugins(tst_qmlbasicapp) +endif() diff --git a/tests/auto/qml/qmlbasicapp/TimeExample/CMakeLists.txt b/tests/auto/qml/qmlbasicapp/TimeExample/CMakeLists.txt index 2e55d6c47c..91bc6dc89e 100644 --- a/tests/auto/qml/qmlbasicapp/TimeExample/CMakeLists.txt +++ b/tests/auto/qml/qmlbasicapp/TimeExample/CMakeLists.txt @@ -1,4 +1,4 @@ -add_library(qmlqtimeexample STATIC) +qt6_add_library(qmlqtimeexample STATIC) qt_autogen_tools_initial_setup(qmlqtimeexample) qt6_add_qml_module(qmlqtimeexample VERSION 1.0 diff --git a/tests/auto/qml/qmlbasicapp/TimeExample/timemodel.h b/tests/auto/qml/qmlbasicapp/TimeExample/timemodel.h index 62827dac5e..75e7d3704c 100644 --- a/tests/auto/qml/qmlbasicapp/TimeExample/timemodel.h +++ b/tests/auto/qml/qmlbasicapp/TimeExample/timemodel.h @@ -55,6 +55,7 @@ #include <QtCore/qdatetime.h> #include <QtCore/qbasictimer.h> #include <QtCore/qcoreapplication.h> +#include <QtCore/qproperty.h> class TimeModel : public QObject { diff --git a/tests/auto/qml/qmlbasicapp/main.qml b/tests/auto/qml/qmlbasicapp/main.qml index 85dfa394d2..a01b56d35d 100644 --- a/tests/auto/qml/qmlbasicapp/main.qml +++ b/tests/auto/qml/qmlbasicapp/main.qml @@ -57,4 +57,7 @@ Clock { // this class is defined in QML (Clock.qml) hours: time.hour minutes: time.minute property Extension extension // from BasicExtension + property More more: More {} + property string fromESModule: ESModule.eee() + property string fromJSFile: Less.bar() } diff --git a/tests/auto/qml/qmlbasicapp/manual_imports.cpp b/tests/auto/qml/qmlbasicapp/manual_imports.cpp new file mode 100644 index 0000000000..9e585105d4 --- /dev/null +++ b/tests/auto/qml/qmlbasicapp/manual_imports.cpp @@ -0,0 +1,32 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQml/qqmlextensionplugin.h> + +Q_IMPORT_QML_PLUGIN(TimeExamplePlugin) +Q_IMPORT_QML_PLUGIN(BasicExtension) diff --git a/tests/auto/qml/qmlbasicapp/tst_qmlbasicapp.cpp b/tests/auto/qml/qmlbasicapp/tst_qmlbasicapp.cpp index e2fb42bf2b..a6c6e4accd 100644 --- a/tests/auto/qml/qmlbasicapp/tst_qmlbasicapp.cpp +++ b/tests/auto/qml/qmlbasicapp/tst_qmlbasicapp.cpp @@ -27,7 +27,6 @@ ****************************************************************************/ #include <QQmlEngine> -#include <QtQml/qqmlextensionplugin.h> #include <QQmlComponent> #include <QObject> #include <qtest.h> @@ -45,6 +44,9 @@ private slots: void tst_basicapp::loadComponent() { QQmlEngine engine; +#ifdef Q_OS_ANDROID + engine.addImportPath(":/"); +#endif QQmlComponent c(&engine, QStringLiteral("qrc:/BasicApp/main.qml")); QVERIFY2(c.isReady(), qPrintable(c.errorString())); QScopedPointer o(c.create()); @@ -58,6 +60,13 @@ void tst_basicapp::loadComponent() const int minute = o->property("minutes").toInt(); QVERIFY(minute >= time.minute() - 1); QVERIFY(minute <= time.minute() + 1); + + QObject *more = qvariant_cast<QObject*>(o->property("more")); + QVERIFY(more); + QCOMPARE(more->objectName(), QStringLiteral("ui.qml")); + + QCOMPARE(o->property("fromESModule").toString(), QStringLiteral("eee")); + QCOMPARE(o->property("fromJSFile").toString(), QStringLiteral("bar")); } void tst_basicapp::resourceFiles() @@ -77,10 +86,13 @@ void tst_basicapp::resourceFiles() void tst_basicapp::fileSystemFiles() { +#ifdef Q_OS_ANDROID + QSKIP("This test is not valid for Android, because the files can exist only as resources."); +#endif const QString basedir = QCoreApplication::applicationDirPath(); - QVERIFY(QFile::exists(basedir + QStringLiteral("/main.qml"))); - QVERIFY(QFile::exists(basedir + QStringLiteral("/qmldir"))); - QVERIFY(QFile::exists(basedir + QStringLiteral("/tst_qmlbasicapp.qmltypes"))); + QVERIFY(QFile::exists(basedir + QStringLiteral("/BasicApp/main.qml"))); + QVERIFY(QFile::exists(basedir + QStringLiteral("/BasicApp/qmldir"))); + QVERIFY(QFile::exists(basedir + QStringLiteral("/BasicApp/tst_qmlbasicapp.qmltypes"))); QVERIFY(QFile::exists(basedir + QStringLiteral("/TimeExample/Clock.qml"))); QVERIFY(QFile::exists(basedir + QStringLiteral("/TimeExample/center.png"))); @@ -93,8 +105,13 @@ void tst_basicapp::fileSystemFiles() void tst_basicapp::qmldirContents() { +#ifdef Q_OS_ANDROID + const QString basedir = QStringLiteral(":"); // Use qrc resource path on Android +#else + const QString basedir = QCoreApplication::applicationDirPath(); +#endif { - QFile qmldir(QCoreApplication::applicationDirPath() + "/qmldir"); + QFile qmldir(basedir + "/BasicApp/qmldir"); QVERIFY(qmldir.open(QIODevice::ReadOnly)); const QByteArray contents = qmldir.readAll(); QVERIFY(contents.contains("module BasicApp")); @@ -109,7 +126,7 @@ void tst_basicapp::qmldirContents() } { - QFile qmldir(QCoreApplication::applicationDirPath() + "/TimeExample/qmldir"); + QFile qmldir(basedir + "/TimeExample/qmldir"); QVERIFY(qmldir.open(QIODevice::ReadOnly)); const QByteArray contents = qmldir.readAll(); QVERIFY(contents.contains("module TimeExample")); @@ -124,9 +141,18 @@ void tst_basicapp::qmldirContents() QVERIFY(qmldirInResources.open(QIODevice::ReadOnly)); QCOMPARE(qmldirInResources.readAll(), contents); } -} -Q_IMPORT_QML_PLUGIN(BasicExtension) + { + QFile qmldir(basedir + "/BasicExtension/qmldir"); + QVERIFY(qmldir.open(QIODevice::ReadOnly)); + const QByteArray contents = qmldir.readAll(); + QVERIFY(contents.contains("More 1.0 More.ui.qml")); + QVERIFY(contents.contains("Less.js")); + QVERIFY(contents.contains("ESModule.mjs")); + QVERIFY(!contents.contains("lowerCase.js")); + QVERIFY(!contents.contains("lowerCaseModule.mjs")); + } +} QTEST_MAIN(tst_basicapp) #include "tst_qmlbasicapp.moc" diff --git a/tests/auto/qml/qmlcachegen/CMakeLists.txt b/tests/auto/qml/qmlcachegen/CMakeLists.txt index 3848e79971..7f22c14f92 100644 --- a/tests/auto/qml/qmlcachegen/CMakeLists.txt +++ b/tests/auto/qml/qmlcachegen/CMakeLists.txt @@ -12,22 +12,19 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qmlcachegen SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qmlcachegen.cpp - INCLUDE_DIRECTORIES - ../../shared + scriptstringprops.h PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) qt6_add_qml_module(tst_qmlcachegen URI cachegentest VERSION 1.0 - NO_CREATE_PLUGIN_TARGET - NO_GENERATE_PLUGIN_SOURCE ) set(qmake_workerscripts_test_qml_files @@ -103,6 +100,7 @@ set(qmake_immediate_qml_files "data/script.mjs" "data/utils.mjs" "data/versionchecks.qml" + "data/scriptstring.qml" ) qt6_target_qml_sources(tst_qmlcachegen @@ -155,3 +153,8 @@ qt_internal_extend_target(tst_qmlcachegen CONDITION NOT ANDROID AND NOT IOS DEFINES QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\" ) + +qt_internal_extend_target(tst_qmlcachegen CONDITION CMAKE_CROSSCOMPILING + DEFINES + QTEST_CROSS_COMPILED +) diff --git a/tests/auto/qml/qmlcachegen/data/scriptstring.qml b/tests/auto/qml/qmlcachegen/data/scriptstring.qml new file mode 100644 index 0000000000..64c73ccdbc --- /dev/null +++ b/tests/auto/qml/qmlcachegen/data/scriptstring.qml @@ -0,0 +1,9 @@ +import cachegentest + +ScriptStringProps { + undef: undefined + nul: null + str: "hello" + num: 42 + bol: true +} diff --git a/tests/auto/qml/qmlcachegen/scriptstringprops.h b/tests/auto/qml/qmlcachegen/scriptstringprops.h new file mode 100644 index 0000000000..e471da92b5 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/scriptstringprops.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef SCRIPT_STRING_PROPS_H +#define SCRIPT_STRING_PROPS_H + +#include <QObject> +#include <QQmlScriptString> +#include <qqml.h> + +class ScriptStringProps :public QObject +{ + Q_OBJECT + QML_ELEMENT + + Q_PROPERTY(QQmlScriptString undef READ undef WRITE setUndef NOTIFY undefChanged) + Q_PROPERTY(QQmlScriptString nul READ nul WRITE setNul NOTIFY nulChanged) + Q_PROPERTY(QQmlScriptString str READ str WRITE setStr NOTIFY strChanged) + Q_PROPERTY(QQmlScriptString num READ num WRITE setNum NOTIFY numChanged) + Q_PROPERTY(QQmlScriptString bol READ bol WRITE setBol NOTIFY bolChanged) + +public: + const QQmlScriptString &undef() const; + void setUndef(const QQmlScriptString &newUndef); + + const QQmlScriptString &nul() const; + void setNul(const QQmlScriptString &newNul); + + const QQmlScriptString &str() const; + void setStr(const QQmlScriptString &newStr); + + const QQmlScriptString &num() const; + void setNum(const QQmlScriptString &newNum); + + const QQmlScriptString &bol() const; + void setBol(const QQmlScriptString &newBol); +signals: + void undefChanged(); + + void nulChanged(); + + void strChanged(); + + void numChanged(); + + void bolChanged(); + +public: + QQmlScriptString m_undef; + QQmlScriptString m_nul; + QQmlScriptString m_str; + QQmlScriptString m_num; + QQmlScriptString m_bol; +}; + +#endif diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index 8fdfecb379..a2639bc532 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -37,14 +37,21 @@ #include <QLoggingCategory> #include <private/qqmlcomponent_p.h> #include <private/qqmlscriptdata_p.h> +#include <private/qv4compileddata_p.h> #include <qtranslator.h> +#include <qqmlscriptstring.h> +#include <QString> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> +#include "scriptstringprops.h" class tst_qmlcachegen: public QQmlDataTest { Q_OBJECT +public: + tst_qmlcachegen(); + private slots: void initTestCase() override; @@ -78,6 +85,9 @@ private slots: void parameterAdjustment(); void inlineComponent(); void posthocRequired(); + + void scriptStringCachegenInteraction(); + void saveableUnitPointer(); }; // A wrapper around QQmlComponent to ensure the temporary reference counts @@ -104,6 +114,10 @@ public: static bool generateCache(const QString &qmlFileName, QByteArray *capturedStderr = nullptr) { +#if defined(QTEST_CROSS_COMPILED) + QTest::qFail("You cannot call qmlcachegen on the target.", __FILE__, __LINE__); + return false; +#endif QProcess proc; if (capturedStderr == nullptr) proc.setProcessChannelMode(QProcess::ForwardedChannels); @@ -122,6 +136,11 @@ static bool generateCache(const QString &qmlFileName, QByteArray *capturedStderr return proc.exitCode() == 0; } +tst_qmlcachegen::tst_qmlcachegen() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_qmlcachegen::initTestCase() { qputenv("QML_FORCE_DISK_CACHE", "1"); @@ -137,6 +156,10 @@ void tst_qmlcachegen::initTestCase() void tst_qmlcachegen::loadGeneratedFile() { +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + QTemporaryDir tempDir; QVERIFY(tempDir.isValid()); @@ -199,6 +222,10 @@ public: void tst_qmlcachegen::translationExpressionSupport() { +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + QTemporaryDir tempDir; QVERIFY(tempDir.isValid()); @@ -244,6 +271,10 @@ void tst_qmlcachegen::translationExpressionSupport() void tst_qmlcachegen::signalHandlerParameters() { +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + QTemporaryDir tempDir; QVERIFY(tempDir.isValid()); @@ -307,6 +338,10 @@ void tst_qmlcachegen::signalHandlerParameters() void tst_qmlcachegen::errorOnArgumentsInSignalHandler() { +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + QTemporaryDir tempDir; QVERIFY(tempDir.isValid()); @@ -332,6 +367,10 @@ void tst_qmlcachegen::errorOnArgumentsInSignalHandler() void tst_qmlcachegen::aheadOfTimeCompilation() { +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + QTemporaryDir tempDir; QVERIFY(tempDir.isValid()); @@ -372,21 +411,33 @@ void tst_qmlcachegen::versionChecksForAheadOfTimeUnits() Q_ASSERT(!temporaryModifiedCachedUnit); QQmlMetaType::CachedUnitLookupError error = QQmlMetaType::CachedUnitLookupError::NoError; + QLoggingCategory::setFilterRules("qt.qml.diskcache.debug=true"); const QQmlPrivate::CachedQmlUnit *originalUnit = QQmlMetaType::findCachedCompilationUnit( QUrl("qrc:/data/versionchecks.qml"), &error); + QLoggingCategory::setFilterRules(QString()); QVERIFY(originalUnit); QV4::CompiledData::Unit *tweakedUnit = (QV4::CompiledData::Unit *)malloc(originalUnit->qmlData->unitSize); memcpy(reinterpret_cast<void *>(tweakedUnit), reinterpret_cast<const void *>(originalUnit->qmlData), originalUnit->qmlData->unitSize); tweakedUnit->version = QV4_DATA_STRUCTURE_VERSION - 1; - temporaryModifiedCachedUnit = new QQmlPrivate::CachedQmlUnit{tweakedUnit, nullptr, nullptr}; - auto testHandler = [](const QUrl &url) -> const QQmlPrivate::CachedQmlUnit * { + const auto testHandler = [](const QUrl &url) -> const QQmlPrivate::CachedQmlUnit * { if (url == QUrl("qrc:/data/versionchecks.qml")) return temporaryModifiedCachedUnit; return nullptr; }; + + const auto dropModifiedUnit = qScopeGuard([&testHandler]() { + Q_ASSERT(temporaryModifiedCachedUnit); + free(const_cast<QV4::CompiledData::Unit *>(temporaryModifiedCachedUnit->qmlData)); + delete temporaryModifiedCachedUnit; + temporaryModifiedCachedUnit = nullptr; + + QQmlMetaType::removeCachedUnitLookupFunction(testHandler); + }); + + temporaryModifiedCachedUnit = new QQmlPrivate::CachedQmlUnit{tweakedUnit, nullptr, nullptr}; QQmlMetaType::prependCachedUnitLookupFunction(testHandler); { @@ -400,13 +451,6 @@ void tst_qmlcachegen::versionChecksForAheadOfTimeUnits() CleanlyLoadingComponent component(&engine, QUrl("qrc:/data/versionchecks.qml")); QCOMPARE(component.status(), QQmlComponent::Ready); } - - Q_ASSERT(temporaryModifiedCachedUnit); - free(const_cast<QV4::CompiledData::Unit *>(temporaryModifiedCachedUnit->qmlData)); - delete temporaryModifiedCachedUnit; - temporaryModifiedCachedUnit = nullptr; - - QQmlMetaType::removeCachedUnitLookupFunction(testHandler); } void tst_qmlcachegen::retainedResources() @@ -444,6 +488,10 @@ void tst_qmlcachegen::workerScripts() void tst_qmlcachegen::functionExpressions() { +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + QTemporaryDir tempDir; QVERIFY(tempDir.isValid()); @@ -541,6 +589,10 @@ void tst_qmlcachegen::qrcScriptImport() void tst_qmlcachegen::fsScriptImport() { +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + QTemporaryDir tempDir; QVERIFY(tempDir.isValid()); @@ -666,6 +718,10 @@ void tst_qmlcachegen::reproducibleCache_data() void tst_qmlcachegen::reproducibleCache() { +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + QFETCH(QString, filePath); QFile file(filePath); @@ -697,6 +753,10 @@ void tst_qmlcachegen::parameterAdjustment() void tst_qmlcachegen::inlineComponent() { +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + QByteArray errors; bool ok = generateCache(testFile("inlineComponentWithId.qml"), &errors); QVERIFY2(ok, errors); @@ -709,6 +769,10 @@ void tst_qmlcachegen::inlineComponent() void tst_qmlcachegen::posthocRequired() { +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + bool ok = generateCache(testFile("posthocrequired.qml")); QVERIFY(ok); QQmlEngine engine; @@ -718,6 +782,125 @@ void tst_qmlcachegen::posthocRequired() QVERIFY(component.errorString().contains(QStringLiteral("Required property x was not initialized"))); } +void tst_qmlcachegen::scriptStringCachegenInteraction() +{ +#if defined(QTEST_CROSS_COMPILED) + QSKIP("Cannot call qmlcachegen on cross-compiled target."); +#endif + + bool ok = generateCache(testFile("scriptstring.qml")); + QVERIFY(ok); + QQmlEngine engine; + CleanlyLoadingComponent component(&engine, testFileUrl("scriptstring.qml")); + QScopedPointer<QObject> root(component.create()); + QVERIFY2(!root.isNull(), qPrintable(component.errorString())); + auto scripty = qobject_cast<ScriptStringProps *>(root.get()); + QVERIFY(scripty); + + QVERIFY(scripty->m_undef.isUndefinedLiteral()); + QVERIFY(scripty->m_nul.isNullLiteral()); + QCOMPARE(scripty->m_str.stringLiteral(), u"hello"_qs); + QCOMPARE(scripty->m_num.numberLiteral(&ok), 42); + ok = false; + scripty->m_bol.booleanLiteral(&ok); + QVERIFY(ok); +} + +void tst_qmlcachegen::saveableUnitPointer() +{ + QV4::CompiledData::Unit unit; + unit.flags = QV4::CompiledData::Unit::StaticData | QV4::CompiledData::Unit::IsJavascript; + const auto flags = unit.flags; + + QV4::CompiledData::SaveableUnitPointer pointer(&unit); + + QVERIFY(pointer.saveToDisk<char>([](const char *, quint32) { return true; })); + QCOMPARE(unit.flags, flags); +} + +const QQmlScriptString &ScriptStringProps::undef() const +{ + return m_undef; +} + + + +void ScriptStringProps::setUndef(const QQmlScriptString &newUndef) +{ + if (m_undef == newUndef) + return; + m_undef = newUndef; + emit undefChanged(); +} + + + +const QQmlScriptString &ScriptStringProps::nul() const +{ + return m_nul; +} + + + +void ScriptStringProps::setNul(const QQmlScriptString &newNul) +{ + if (m_nul == newNul) + return; + m_nul = newNul; + emit nulChanged(); +} + + + +const QQmlScriptString &ScriptStringProps::str() const +{ + return m_str; +} + + + +void ScriptStringProps::setStr(const QQmlScriptString &newStr) +{ + if (m_str == newStr) + return; + m_str = newStr; + emit strChanged(); +} + + + +const QQmlScriptString &ScriptStringProps::num() const +{ + return m_num; +} + + + +void ScriptStringProps::setNum(const QQmlScriptString &newNum) +{ + if (m_num == newNum) + return; + m_num = newNum; + emit numChanged(); +} + + + +const QQmlScriptString &ScriptStringProps::bol() const +{ + return m_bol; +} + + + +void ScriptStringProps::setBol(const QQmlScriptString &newBol) +{ + if (m_bol == newBol) + return; + m_bol = newBol; + emit bolChanged(); +} + QTEST_GUILESS_MAIN(tst_qmlcachegen) #include "tst_qmlcachegen.moc" diff --git a/tests/auto/qml/qmlcompiler_manual/CMakeLists.txt b/tests/auto/qml/qmlcompiler_manual/CMakeLists.txt index ebd207e94b..92ba3fc122 100644 --- a/tests/auto/qml/qmlcompiler_manual/CMakeLists.txt +++ b/tests/auto/qml/qmlcompiler_manual/CMakeLists.txt @@ -6,20 +6,18 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qmlcompiler_manual SOURCES - ../../shared/util.cpp ../../shared/util.h testclasses.h tst_qmlcompiler_manual.cpp - INCLUDE_DIRECTORIES - ../../shared LIBRARIES Qt::CorePrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate + TESTDATA ${test_data} ) qt6_add_qml_module(tst_qmlcompiler_manual VERSION 1.0 URI "QmltcManualTests" - NO_CREATE_PLUGIN_TARGET QML_FILES ${test_data} ) diff --git a/tests/auto/qml/qmlcompiler_manual/tst_qmlcompiler_manual.cpp b/tests/auto/qml/qmlcompiler_manual/tst_qmlcompiler_manual.cpp index ae90aaa34d..a42dc52556 100644 --- a/tests/auto/qml/qmlcompiler_manual/tst_qmlcompiler_manual.cpp +++ b/tests/auto/qml/qmlcompiler_manual/tst_qmlcompiler_manual.cpp @@ -38,7 +38,7 @@ #include <private/qqmlengine_p.h> #include <private/qqmltypedata_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <array> #include <memory> @@ -47,6 +47,9 @@ class tst_qmlcompiler_manual : public QQmlDataTest { Q_OBJECT +public: + tst_qmlcompiler_manual(); + private slots: void cppBinding(); void signalHandlers(); @@ -163,6 +166,11 @@ HelloWorld::HelloWorld(QQmlEngine *e, QObject *parent) QUrl HelloWorld::url = QUrl(); // workaround +tst_qmlcompiler_manual::tst_qmlcompiler_manual() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_qmlcompiler_manual::cppBinding() { QQmlEngine e; diff --git a/tests/auto/qml/qmldiskcache/dummy_imports.qml b/tests/auto/qml/qmldiskcache/dummy_imports.qml index b9a196e188..63d33cbea6 100644 --- a/tests/auto/qml/qmldiskcache/dummy_imports.qml +++ b/tests/auto/qml/qmldiskcache/dummy_imports.qml @@ -1,8 +1,7 @@ // This file exists for the sole purpose for qmlimportscanner to find // which modules it needs to extract for deployment. -// Otherwise, it fails to find the imports that are expressed in C++ -// code in tst_parserstress.cpp +// Otherwise, it fails to find the imports that are expressed in C++. -import QtQuick 2.0 +import QtQuick -QtObject { } // This is needed in order to keep importscanner happy +QtObject { } diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index 593eea3e3a..d84aaaeba3 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -65,6 +65,7 @@ private slots: void cppRegisteredSingletonDependency(); void cacheModuleScripts(); void reuseStaticMappings(); + void invalidateSaveLoadCache(); private: QDir m_qmlCacheDirectory; @@ -346,7 +347,7 @@ void tst_qmldiskcache::regenerateAfterChange() const QV4::CompiledData::Object *obj = qmlUnit->objectAt(0); QCOMPARE(quint32(obj->nBindings), quint32(1)); - QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Script)); + QCOMPARE(obj->bindingTable()->type(), QV4::CompiledData::Binding::Type_Script); QCOMPARE(quint32(obj->bindingTable()->value.compiledScriptIndex), quint32(0)); QCOMPARE(quint32(testUnit->functionTableSize), quint32(1)); @@ -374,7 +375,7 @@ void tst_qmldiskcache::regenerateAfterChange() const QV4::CompiledData::Object *obj = qmlUnit->objectAt(0); QCOMPARE(quint32(obj->nBindings), quint32(2)); - QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Number)); + QCOMPARE(obj->bindingTable()->type(), QV4::CompiledData::Binding::Type_Number); const QV4::Value value(testUnit->constants()[obj->bindingTable()->value.constantValueIndex]); QCOMPARE(value.doubleValue(), double(42)); @@ -418,7 +419,7 @@ void tst_qmldiskcache::registerImportForImplicitComponent() const QV4::CompiledData::Object *obj = qmlUnit->objectAt(0); QCOMPARE(quint32(obj->nBindings), quint32(1)); - QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Object)); + QCOMPARE(obj->bindingTable()->type(), QV4::CompiledData::Binding::Type_Object); const QV4::CompiledData::Object *implicitComponent = qmlUnit->objectAt(obj->bindingTable()->value.objectIndex); QCOMPARE(testUnit->stringAtInternal(implicitComponent->inheritedTypeNameIndex), QStringLiteral("QmlInternals.") + componentType.elementName()); @@ -550,6 +551,7 @@ void tst_qmldiskcache::recompileAfterChange() CleanlyLoadingComponent component(&engine, testCompiler.testFilePath); QScopedPointer<TypeVersion2> obj(qobject_cast<TypeVersion2*>(component.create())); QVERIFY(!obj.isNull()); + qDebug() << obj->property("x"); QVERIFY(QFileInfo(testCompiler.cacheFilePath).lastModified() > initialCacheTimeStamp); } } @@ -1030,6 +1032,112 @@ void tst_qmldiskcache::reuseStaticMappings() QCOMPARE(testCompiler.unitData(), data1); } +class AParent : public QObject +{ + Q_OBJECT + Q_PROPERTY(int x MEMBER x) +public: + AParent(QObject *parent = nullptr) : QObject(parent) {} + int x = 25; +}; + +class BParent : public QObject +{ + Q_OBJECT + + // Insert y before x, to change the property index of x + Q_PROPERTY(int y MEMBER y) + + Q_PROPERTY(int x MEMBER x) +public: + BParent(QObject *parent = nullptr) : QObject(parent) {} + int y = 13; + int x = 25; +}; + +static QString writeTempFile( + const QTemporaryDir &tempDir, const QString &fileName, const char *contents) { + QFile f(tempDir.path() + '/' + fileName); + const bool ok = f.open(QIODevice::WriteOnly | QIODevice::Truncate); + Q_ASSERT(ok); + f.write(contents); + return f.fileName(); +}; + +void tst_qmldiskcache::invalidateSaveLoadCache() +{ + qmlRegisterType<AParent>("Base", 1, 0, "Parent"); + QQmlEngine e; + + // If you store a CU to a .qmlc file at run time, the .qmlc file will contain + // alias entries with the encodedMetaPropertyIndex pre-resolved. That's in + // contrast to .qmlc files generated ahead of time. Exploit that to cause + // a need to recompile the file. + + QTemporaryDir tempDir; + const QString fileName = writeTempFile( + tempDir, QLatin1String("a.qml"), + "import Base\nParent { id: self; property alias z: self.x }"); + const QUrl url = QUrl::fromLocalFile(fileName); + waitForFileSystem(); + + { + QQmlComponent a(&e, url); + QVERIFY2(a.isReady(), qPrintable(a.errorString())); + QScopedPointer<QObject> ao(a.create()); + QVERIFY(!ao.isNull()); + AParent *ap = qobject_cast<AParent *>(ao.data()); + QCOMPARE(ap->property("z").toInt(), ap->x); + } + + QString errorString; + QQmlRefPointer<QV4::ExecutableCompilationUnit> oldUnit + = QV4::ExecutableCompilationUnit::create(); + QVERIFY2(oldUnit->loadFromDisk(url, QFileInfo(fileName).lastModified(), &errorString), qPrintable(errorString)); + + // Produce a checksum mismatch. + e.clearComponentCache(); + qmlClearTypeRegistrations(); + qmlRegisterType<BParent>("Base", 1, 0, "Parent"); + + { + QQmlComponent b(&e, url); + QVERIFY2(b.isReady(), qPrintable(b.errorString())); + QScopedPointer<QObject> bo(b.create()); + QVERIFY(!bo.isNull()); + BParent *bp = qobject_cast<BParent *>(bo.data()); + QCOMPARE(bp->property("z").toInt(), bp->x); + } + + // Make it recompile again. + e.clearComponentCache(); + { + QFile file(fileName); + file.open(QIODevice::WriteOnly | QIODevice::Append); + file.write(" "); + } + waitForFileSystem(); + + { + QQmlComponent b(&e, url); + QVERIFY2(b.isReady(), qPrintable(b.errorString())); + QScopedPointer<QObject> bo(b.create()); + QVERIFY(!bo.isNull()); + BParent *bp = qobject_cast<BParent *>(bo.data()); + QCOMPARE(bp->property("z").toInt(), bp->x); + } + + // Verify that the mapped unit data is actually different now. + // The cache should have been invalidated after all. + // So, now we should be able to load a freshly written CU. + + QQmlRefPointer<QV4::ExecutableCompilationUnit> unit + = QV4::ExecutableCompilationUnit::create(); + QVERIFY2(unit->loadFromDisk(url, QFileInfo(fileName).lastModified(), &errorString), qPrintable(errorString)); + + QVERIFY(unit->unitData() != oldUnit->unitData()); +} + QTEST_MAIN(tst_qmldiskcache) #include "tst_qmldiskcache.moc" diff --git a/tests/auto/qml/qmlformat/CMakeLists.txt b/tests/auto/qml/qmlformat/CMakeLists.txt index 8d5133ccf7..6716a509e1 100644 --- a/tests/auto/qml/qmlformat/CMakeLists.txt +++ b/tests/auto/qml/qmlformat/CMakeLists.txt @@ -12,15 +12,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qmlformat SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qmlformat.cpp DEFINES SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::TestPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qmlformat/data/Annotations.formatted.qml b/tests/auto/qml/qmlformat/data/Annotations.formatted.qml index 2fccb05e6e..ca58c90ecf 100644 --- a/tests/auto/qml/qmlformat/data/Annotations.formatted.qml +++ b/tests/auto/qml/qmlformat/data/Annotations.formatted.qml @@ -42,7 +42,6 @@ Item { @Annotate { } anchors.fill: parent - @AnnotateMore { property int x: 5 } @@ -57,7 +56,6 @@ Item { anchors.fill: parent legend.alignment: Qt.AlignBottom antialiasing: true - @ExtraAnnotation { signal pippo } @@ -90,7 +88,6 @@ Item { value: 6.8 } } - @SignalAnnotation { implicit: true } @@ -101,7 +98,6 @@ Item { function foo(x) { return 42; } - @BindingAnn { bType: 1 } @@ -125,7 +121,6 @@ Item { duration: 34 } } - @SuperComplete { binding: late } diff --git a/tests/auto/qml/qmlformat/data/Example1.formatted.2spaces.qml b/tests/auto/qml/qmlformat/data/Example1.formatted.2spaces.qml index 48a1acf483..8b181f607e 100644 --- a/tests/auto/qml/qmlformat/data/Example1.formatted.2spaces.qml +++ b/tests/auto/qml/qmlformat/data/Example1.formatted.2spaces.qml @@ -55,7 +55,6 @@ Item { // More orphans property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3] - property bool something_computed: function (x) { const PI = 3, DAYS_PER_YEAR = 365.25; var x = 3 + 2; @@ -129,6 +128,7 @@ Item { }() default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool + myFavouriteThings: [ // This is an orphan @@ -147,9 +147,7 @@ Item { Text { text: "Bla" - signal boo(int count, int times, real duration) - required property string batman } diff --git a/tests/auto/qml/qmlformat/data/Example1.formatted.qml b/tests/auto/qml/qmlformat/data/Example1.formatted.qml index a679e8a010..cb8865d94e 100644 --- a/tests/auto/qml/qmlformat/data/Example1.formatted.qml +++ b/tests/auto/qml/qmlformat/data/Example1.formatted.qml @@ -55,7 +55,6 @@ Item { // More orphans property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3] - property bool something_computed: function (x) { const PI = 3, DAYS_PER_YEAR = 365.25; var x = 3 + 2; @@ -129,6 +128,7 @@ Item { }() default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool + myFavouriteThings: [ // This is an orphan @@ -147,9 +147,7 @@ Item { Text { text: "Bla" - signal boo(int count, int times, real duration) - required property string batman } diff --git a/tests/auto/qml/qmlformat/data/Example1.formatted.tabs.qml b/tests/auto/qml/qmlformat/data/Example1.formatted.tabs.qml index 34b3467cb4..ef964f6f60 100644 --- a/tests/auto/qml/qmlformat/data/Example1.formatted.tabs.qml +++ b/tests/auto/qml/qmlformat/data/Example1.formatted.tabs.qml @@ -55,7 +55,6 @@ Item { // More orphans property variant some_array_literal: [30, 20, Math["PI"], [4, 3, 2], "foo", 0.3] - property bool something_computed: function (x) { const PI = 3, DAYS_PER_YEAR = 365.25; var x = 3 + 2; @@ -129,6 +128,7 @@ Item { }() default property bool some_default_bool: 500 % 5 !== 0 // some_default_bool + myFavouriteThings: [ // This is an orphan @@ -147,9 +147,7 @@ Item { Text { text: "Bla" - signal boo(int count, int times, real duration) - required property string batman } diff --git a/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.formatted.qml b/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.formatted.qml new file mode 100644 index 0000000000..edbb12c6e6 --- /dev/null +++ b/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.formatted.qml @@ -0,0 +1,37 @@ +import QtQuick + +Item { + + function f() { + var count = 0; + class Person { + constructor(name){ + this._name = name; + } + } + class Employee extends Person { + constructor(name, age){ + super(name); + this._name = name; + this._age = age; + ++count; + } + + doWork(){} + + /* do we get the comment? */ get name(){ + return this._name.toUpperCase(); + } + + set name(newName){ + if (newName) { + this._name = newName; + } + } + + static get count(){ + return count; + } + } + } +} diff --git a/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.qml b/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.qml new file mode 100644 index 0000000000..268859d3cc --- /dev/null +++ b/tests/auto/qml/qmlformat/data/ecmaScriptClassInQml.qml @@ -0,0 +1,45 @@ +import QtQuick + +Item { + +function f() { + +var count = 0; + +class Person { + constructor(name) { + this._name = name + } +} + +class Employee extends Person{ + + + constructor(name, age) { + super(name); + this._name = name; + this._age = age; + ++count; + } + + doWork() { + + } + + get /* do we get the comment? */ name() { + return this._name.toUpperCase(); + } + + set name(newName){ + if(newName){ + this._name = newName; + } + } + + static get count() { return count;} +} + + +} + +}
\ No newline at end of file diff --git a/tests/auto/qml/qmlformat/data/largeBindings.formatted.qml b/tests/auto/qml/qmlformat/data/largeBindings.formatted.qml index 70283dade6..879bf297b2 100644 --- a/tests/auto/qml/qmlformat/data/largeBindings.formatted.qml +++ b/tests/auto/qml/qmlformat/data/largeBindings.formatted.qml @@ -7,6 +7,7 @@ QtObject { var x = 300; console.log(x); } + small1: 3 small2: foo smallButNeedsBraces: if (foo) { diff --git a/tests/auto/qml/qmlformat/data/nestedFunctions.formatted.qml b/tests/auto/qml/qmlformat/data/nestedFunctions.formatted.qml index 522e844201..5536ecf513 100644 --- a/tests/auto/qml/qmlformat/data/nestedFunctions.formatted.qml +++ b/tests/auto/qml/qmlformat/data/nestedFunctions.formatted.qml @@ -3,6 +3,7 @@ Item { function nested() {} foo(); } + function b() { function nested() {} bar(); diff --git a/tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml b/tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml index 3084ab7951..354f2ba979 100644 --- a/tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml +++ b/tests/auto/qml/qmlformat/data/readOnlyProps.formatted.qml @@ -6,7 +6,6 @@ QtObject { id: test signal foo } - // End comment // Testing UiArrayBinding diff --git a/tests/auto/qml/qmlformat/data/statesAndTransitions.formatted.qml b/tests/auto/qml/qmlformat/data/statesAndTransitions.formatted.qml index f72e9d8195..40cf5068da 100644 --- a/tests/auto/qml/qmlformat/data/statesAndTransitions.formatted.qml +++ b/tests/auto/qml/qmlformat/data/statesAndTransitions.formatted.qml @@ -1,5 +1,6 @@ QtObject { id: foo + states: [ State { } diff --git a/tests/auto/qml/qmlformat/data/verbatimString.formatted.qml b/tests/auto/qml/qmlformat/data/verbatimString.formatted.qml index 65539b538a..84abe38f88 100644 --- a/tests/auto/qml/qmlformat/data/verbatimString.formatted.qml +++ b/tests/auto/qml/qmlformat/data/verbatimString.formatted.qml @@ -1,8 +1,6 @@ Item { property string verbatim1: 'A "verbatim" string!' - property string verbatim2: "A 'verbatim' string\u2757" - property string verbatim3: `400 + 300 is ${400 + 300}. mutliline` diff --git a/tests/auto/qml/qmlformat/tst_qmlformat.cpp b/tests/auto/qml/qmlformat/tst_qmlformat.cpp index f9cf4deafb..843c078f8c 100644 --- a/tests/auto/qml/qmlformat/tst_qmlformat.cpp +++ b/tests/auto/qml/qmlformat/tst_qmlformat.cpp @@ -33,13 +33,15 @@ #include <QString> #include <QTemporaryDir> #include <QtTest/private/qemulationdetector_p.h> - -#include <util.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> class TestQmlformat: public QQmlDataTest { Q_OBJECT +public: + TestQmlformat(); + private Q_SLOTS: void initTestCase() override; @@ -64,6 +66,11 @@ private: bool isInvalidFile(const QFileInfo &fileName) const; }; +TestQmlformat::TestQmlformat() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void TestQmlformat::initTestCase() { QQmlDataTest::initTestCase(); @@ -245,6 +252,9 @@ void TestQmlformat::testFormat_data() << "emptyObject.formatted.qml" << QStringList {}; QTest::newRow("arrow functions") << "arrowFunctions.qml" << "arrowFunctions.formatted.qml" << QStringList {}; + QTest::newRow("ecmaScriptClassInQml") + << "ecmaScriptClassInQml.qml" + << "ecmaScriptClassInQml.formatted.qml" << QStringList {}; } void TestQmlformat::testFormat() diff --git a/tests/auto/qml/qmlimportscanner/CMakeLists.txt b/tests/auto/qml/qmlimportscanner/CMakeLists.txt index ec69f00516..7439910294 100644 --- a/tests/auto/qml/qmlimportscanner/CMakeLists.txt +++ b/tests/auto/qml/qmlimportscanner/CMakeLists.txt @@ -12,12 +12,10 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qmlimportscanner SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qmlimportscanner.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) @@ -35,8 +33,9 @@ qt_internal_extend_target(tst_qmlimportscanner CONDITION NOT ANDROID AND NOT IOS ) # special case begin +string(TOLOWER "${QT_LIBINFIX}" infix_lowercase) qt_internal_extend_target(tst_qmlimportscanner CONDITION DEFINED QT_LIBINFIX DEFINES - LIBINFIX=${QT_LIBINFIX} + LIBINFIX=${infix_lowercase} ) # special case end diff --git a/tests/auto/qml/qmlimportscanner/data/CompositeSingleton.json b/tests/auto/qml/qmlimportscanner/data/CompositeSingleton.json index f8ac3438f9..51b1033a9c 100644 --- a/tests/auto/qml/qmlimportscanner/data/CompositeSingleton.json +++ b/tests/auto/qml/qmlimportscanner/data/CompositeSingleton.json @@ -6,6 +6,7 @@ }, { "classname": "QtQuick2Plugin", + "linkTarget": "Qt6::qtquick2plugin", "name": "QtQuick", "plugin": "qtquick2plugin", "pluginIsOptional": true, @@ -14,6 +15,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -22,6 +24,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -30,6 +33,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/CompositeWithEnum.json b/tests/auto/qml/qmlimportscanner/data/CompositeWithEnum.json index 92d6797bec..e0c37d24c4 100644 --- a/tests/auto/qml/qmlimportscanner/data/CompositeWithEnum.json +++ b/tests/auto/qml/qmlimportscanner/data/CompositeWithEnum.json @@ -6,6 +6,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -14,6 +15,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -22,6 +24,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/CompositeWithinSingleton.json b/tests/auto/qml/qmlimportscanner/data/CompositeWithinSingleton.json index ceed744ea4..e4135c559c 100644 --- a/tests/auto/qml/qmlimportscanner/data/CompositeWithinSingleton.json +++ b/tests/auto/qml/qmlimportscanner/data/CompositeWithinSingleton.json @@ -6,6 +6,7 @@ }, { "classname": "QtQuick2Plugin", + "linkTarget": "Qt6::qtquick2plugin", "name": "QtQuick", "plugin": "qtquick2plugin", "pluginIsOptional": true, @@ -14,6 +15,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -22,6 +24,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -30,6 +33,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/Drawer.qml.json b/tests/auto/qml/qmlimportscanner/data/Drawer.qml.json index 4eac05306a..424c6ca8ee 100644 --- a/tests/auto/qml/qmlimportscanner/data/Drawer.qml.json +++ b/tests/auto/qml/qmlimportscanner/data/Drawer.qml.json @@ -1,6 +1,7 @@ [ { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -9,6 +10,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -17,6 +19,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/Imports.json b/tests/auto/qml/qmlimportscanner/data/Imports.json index 1a1850163d..16b7376713 100644 --- a/tests/auto/qml/qmlimportscanner/data/Imports.json +++ b/tests/auto/qml/qmlimportscanner/data/Imports.json @@ -6,6 +6,7 @@ }, { "classname": "QtQuick2Plugin", + "linkTarget": "Qt6::qtquick2plugin", "name": "QtQuick", "plugin": "qtquick2plugin", "pluginIsOptional": true, @@ -14,6 +15,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -22,6 +24,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -30,6 +33,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/ListProperty.qml.json b/tests/auto/qml/qmlimportscanner/data/ListProperty.qml.json index d647f7f9ae..bd9faec18c 100644 --- a/tests/auto/qml/qmlimportscanner/data/ListProperty.qml.json +++ b/tests/auto/qml/qmlimportscanner/data/ListProperty.qml.json @@ -2,6 +2,7 @@ { "classname": "QtQuick2Plugin", "name": "QtQuick", + "linkTarget": "Qt6::qtquick2plugin", "plugin": "qtquick2plugin", "pluginIsOptional": true, "relativePath": "QtQuick", @@ -15,6 +16,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -23,6 +25,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -31,6 +34,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/QTBUG-45916.js.json b/tests/auto/qml/qmlimportscanner/data/QTBUG-45916.js.json index f7bddd6a91..d132b676ec 100644 --- a/tests/auto/qml/qmlimportscanner/data/QTBUG-45916.js.json +++ b/tests/auto/qml/qmlimportscanner/data/QTBUG-45916.js.json @@ -1,6 +1,7 @@ [ { "classname": "QtQuick2Plugin", + "linkTarget": "Qt6::qtquick2plugin", "name": "QtQuick", "plugin": "qtquick2plugin", "pluginIsOptional": true, @@ -9,6 +10,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -17,6 +19,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -25,6 +28,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/Simple.qml.json b/tests/auto/qml/qmlimportscanner/data/Simple.qml.json index f7bddd6a91..d132b676ec 100644 --- a/tests/auto/qml/qmlimportscanner/data/Simple.qml.json +++ b/tests/auto/qml/qmlimportscanner/data/Simple.qml.json @@ -1,6 +1,7 @@ [ { "classname": "QtQuick2Plugin", + "linkTarget": "Qt6::qtquick2plugin", "name": "QtQuick", "plugin": "qtquick2plugin", "pluginIsOptional": true, @@ -9,6 +10,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -17,6 +19,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -25,6 +28,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/Singleton.json b/tests/auto/qml/qmlimportscanner/data/Singleton.json index ca1d0b2d4d..5600cfc6a2 100644 --- a/tests/auto/qml/qmlimportscanner/data/Singleton.json +++ b/tests/auto/qml/qmlimportscanner/data/Singleton.json @@ -6,6 +6,7 @@ }, { "classname": "QtQuick2Plugin", + "linkTarget": "Qt6::qtquick2plugin", "name": "QtQuick", "plugin": "qtquick2plugin", "pluginIsOptional": true, @@ -14,6 +15,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -22,6 +24,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -30,6 +33,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/Things.json b/tests/auto/qml/qmlimportscanner/data/Things.json index e50902152e..1245539b57 100644 --- a/tests/auto/qml/qmlimportscanner/data/Things.json +++ b/tests/auto/qml/qmlimportscanner/data/Things.json @@ -7,6 +7,7 @@ }, { "classname": "QtQuick2Plugin", + "linkTarget": "Qt6::qtquick2plugin", "name": "QtQuick", "plugin": "qtquick2plugin", "pluginIsOptional": true, @@ -15,6 +16,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -23,6 +25,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -31,6 +34,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/With/Module/A.qml b/tests/auto/qml/qmlimportscanner/data/With/Module/A.qml new file mode 100644 index 0000000000..8fc36a40da --- /dev/null +++ b/tests/auto/qml/qmlimportscanner/data/With/Module/A.qml @@ -0,0 +1,3 @@ +import QtQml + +QtObject {} diff --git a/tests/auto/qml/qmlimportscanner/data/With/Module/qmldir b/tests/auto/qml/qmlimportscanner/data/With/Module/qmldir new file mode 100644 index 0000000000..2338864432 --- /dev/null +++ b/tests/auto/qml/qmlimportscanner/data/With/Module/qmldir @@ -0,0 +1,3 @@ +module Module + +A 1.0 A.qml diff --git a/tests/auto/qml/qmlimportscanner/data/WithOut/Module/A.qml b/tests/auto/qml/qmlimportscanner/data/WithOut/Module/A.qml new file mode 100644 index 0000000000..8fc36a40da --- /dev/null +++ b/tests/auto/qml/qmlimportscanner/data/WithOut/Module/A.qml @@ -0,0 +1,3 @@ +import QtQml + +QtObject {} diff --git a/tests/auto/qml/qmlimportscanner/data/javascriptMethods.qml.json b/tests/auto/qml/qmlimportscanner/data/javascriptMethods.qml.json index cbd409266d..737b90fcc6 100644 --- a/tests/auto/qml/qmlimportscanner/data/javascriptMethods.qml.json +++ b/tests/auto/qml/qmlimportscanner/data/javascriptMethods.qml.json @@ -1,6 +1,7 @@ [ { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -13,6 +14,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -21,6 +23,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/localImport.qml.json b/tests/auto/qml/qmlimportscanner/data/localImport.qml.json index e50902152e..1245539b57 100644 --- a/tests/auto/qml/qmlimportscanner/data/localImport.qml.json +++ b/tests/auto/qml/qmlimportscanner/data/localImport.qml.json @@ -7,6 +7,7 @@ }, { "classname": "QtQuick2Plugin", + "linkTarget": "Qt6::qtquick2plugin", "name": "QtQuick", "plugin": "qtquick2plugin", "pluginIsOptional": true, @@ -15,6 +16,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -23,6 +25,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -31,6 +34,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/parentEnum.qml.json b/tests/auto/qml/qmlimportscanner/data/parentEnum.qml.json index f7bddd6a91..d132b676ec 100644 --- a/tests/auto/qml/qmlimportscanner/data/parentEnum.qml.json +++ b/tests/auto/qml/qmlimportscanner/data/parentEnum.qml.json @@ -1,6 +1,7 @@ [ { "classname": "QtQuick2Plugin", + "linkTarget": "Qt6::qtquick2plugin", "name": "QtQuick", "plugin": "qtquick2plugin", "pluginIsOptional": true, @@ -9,6 +10,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -17,6 +19,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -25,6 +28,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/qmldirImportAndDepend.qml.json b/tests/auto/qml/qmlimportscanner/data/qmldirImportAndDepend.qml.json index e50902152e..1245539b57 100644 --- a/tests/auto/qml/qmlimportscanner/data/qmldirImportAndDepend.qml.json +++ b/tests/auto/qml/qmlimportscanner/data/qmldirImportAndDepend.qml.json @@ -7,6 +7,7 @@ }, { "classname": "QtQuick2Plugin", + "linkTarget": "Qt6::qtquick2plugin", "name": "QtQuick", "plugin": "qtquick2plugin", "pluginIsOptional": true, @@ -15,6 +16,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -23,6 +25,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -31,6 +34,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/qmldirpref.qml b/tests/auto/qml/qmlimportscanner/data/qmldirpref.qml new file mode 100644 index 0000000000..d1b1e80329 --- /dev/null +++ b/tests/auto/qml/qmlimportscanner/data/qmldirpref.qml @@ -0,0 +1,3 @@ +import Module + +A {} diff --git a/tests/auto/qml/qmlimportscanner/data/qtQmlOnly.qml.json b/tests/auto/qml/qmlimportscanner/data/qtQmlOnly.qml.json index 4eac05306a..424c6ca8ee 100644 --- a/tests/auto/qml/qmlimportscanner/data/qtQmlOnly.qml.json +++ b/tests/auto/qml/qmlimportscanner/data/qtQmlOnly.qml.json @@ -1,6 +1,7 @@ [ { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -9,6 +10,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -17,6 +19,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, diff --git a/tests/auto/qml/qmlimportscanner/data/rootPath.json b/tests/auto/qml/qmlimportscanner/data/rootPath.json index 21dbb12629..fe42646665 100644 --- a/tests/auto/qml/qmlimportscanner/data/rootPath.json +++ b/tests/auto/qml/qmlimportscanner/data/rootPath.json @@ -1,6 +1,7 @@ [ { "classname": "QtQuick2Plugin", + "linkTarget": "Qt6::qtquick2plugin", "name": "QtQuick", "plugin": "qtquick2plugin", "pluginIsOptional": true, @@ -9,6 +10,7 @@ }, { "classname": "QtQmlPlugin", + "linkTarget": "Qt6::qmlplugin", "name": "QtQml", "plugin": "qmlplugin", "pluginIsOptional": true, @@ -17,6 +19,7 @@ }, { "classname": "QtQmlModelsPlugin", + "linkTarget": "Qt6::modelsplugin", "name": "QtQml.Models", "plugin": "modelsplugin", "pluginIsOptional": true, @@ -25,6 +28,7 @@ }, { "classname": "QtQmlWorkerScriptPlugin", + "linkTarget": "Qt6::workerscriptplugin", "name": "QtQml.WorkerScript", "plugin": "workerscriptplugin", "pluginIsOptional": true, @@ -53,5 +57,9 @@ "name": "Imports", "relativePath": "Imports", "type": "module" + }, + { + "name": "Module", + "type": "module" } ] diff --git a/tests/auto/qml/qmlimportscanner/tst_qmlimportscanner.cpp b/tests/auto/qml/qmlimportscanner/tst_qmlimportscanner.cpp index 5b8b92748a..2d339cc33d 100644 --- a/tests/auto/qml/qmlimportscanner/tst_qmlimportscanner.cpp +++ b/tests/auto/qml/qmlimportscanner/tst_qmlimportscanner.cpp @@ -29,13 +29,15 @@ #include <QtTest/QtTest> #include <QProcess> #include <QString> - -#include <util.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> class TestQmlimportscanner: public QQmlDataTest { Q_OBJECT +public: + TestQmlimportscanner(); + private Q_SLOTS: void initTestCase() override; @@ -44,6 +46,7 @@ private Q_SLOTS: void rootPath(); void modules_data(); void modules(); + void qmldirPreference(); private: void runQmlimportscanner(const QString &mode, const QString &fileToScan, @@ -52,6 +55,11 @@ private: QString m_qmlimportscannerPath; }; +TestQmlimportscanner::TestQmlimportscanner() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void TestQmlimportscanner::initTestCase() { QQmlDataTest::initTestCase(); @@ -116,6 +124,31 @@ void TestQmlimportscanner::modules() runQmlimportscanner("-qmlFiles", qmlFile.fileName(), testFile(name + ".json")); } +void TestQmlimportscanner::qmldirPreference() +{ + // ### + QStringList with {u"-importPath"_qs, testFile("With")}; + QStringList withOut {u"-importPath"_qs, testFile("WithOut")}; + QStringList genericArgs {u"-qmlFiles"_qs, testFile("qmldirpref.qml"), u"-importPath"_qs, + QLibraryInfo::path(QLibraryInfo::QmlImportsPath)}; + + + // found path should not depend on order of importPath arguments + QStringList argcombis[2] { genericArgs + with + withOut, genericArgs + withOut + with }; + for (const auto &allArgs: argcombis) { + QProcess process; + process.start(m_qmlimportscannerPath, allArgs); + QVERIFY(process.waitForFinished()); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + QCOMPARE(process.exitCode(), 0); + QVERIFY(process.readAllStandardError().isEmpty()); + auto output = process.readAllStandardOutput(); + // check that the "With" path is used, and the "WithOut" path is ignored + QVERIFY(output.contains("With/Module")); + QVERIFY(!output.contains("WithOut/Module")); + } +} + void TestQmlimportscanner::runQmlimportscanner(const QString &mode, const QString &pathToScan, const QString &resultFile) { @@ -157,9 +190,9 @@ void TestQmlimportscanner::runQmlimportscanner(const QString &mode, const QStrin #define STR(A) #A if (object.contains("plugin")) { auto plugin = object["plugin"].toString(); - const auto pos = plugin.lastIndexOf(XSTR(LIBINFIX)); + const auto pos = plugin.lastIndexOf(XSTR(LIBINFIX) "plugin"); if (pos != -1) - object["plugin"] = plugin.left(pos); + object["plugin"] = plugin.left(pos) + "plugin"; } #endif diff --git a/tests/auto/qml/qmllint/CMakeLists.txt b/tests/auto/qml/qmllint/CMakeLists.txt index c69748cc60..15549a93b7 100644 --- a/tests/auto/qml/qmllint/CMakeLists.txt +++ b/tests/auto/qml/qmllint/CMakeLists.txt @@ -12,12 +12,10 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qmllint SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qmllint.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qmllint/data/Cycle/MenuItem.qml b/tests/auto/qml/qmllint/data/Cycle/MenuItem.qml new file mode 100644 index 0000000000..b316a5432c --- /dev/null +++ b/tests/auto/qml/qmllint/data/Cycle/MenuItem.qml @@ -0,0 +1,3 @@ +import QtQml + +MenuItem {} diff --git a/tests/auto/qml/qmllint/data/Cycle/qmldir b/tests/auto/qml/qmllint/data/Cycle/qmldir new file mode 100644 index 0000000000..6b0ba5519a --- /dev/null +++ b/tests/auto/qml/qmllint/data/Cycle/qmldir @@ -0,0 +1,3 @@ +module Cycle + +MenuItem 1.0 MenuItem.qml diff --git a/tests/auto/qml/qmllint/data/LazyAndDirect/Direct.qml b/tests/auto/qml/qmllint/data/LazyAndDirect/Direct.qml new file mode 100644 index 0000000000..fcb08c1e80 --- /dev/null +++ b/tests/auto/qml/qmllint/data/LazyAndDirect/Direct.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + Component.onCompleted: Lazy.setDirect(this) +} diff --git a/tests/auto/qml/qmllint/data/LazyAndDirect/Lazy.qml b/tests/auto/qml/qmllint/data/LazyAndDirect/Lazy.qml new file mode 100644 index 0000000000..1f69d0f16a --- /dev/null +++ b/tests/auto/qml/qmllint/data/LazyAndDirect/Lazy.qml @@ -0,0 +1,8 @@ +pragma Singleton +import QtQml + +QtObject { + property Direct direct + + function setDirect(newDirect : Direct) { direct = newDirect } +} diff --git a/tests/auto/qml/qmllint/data/LazyAndDirect/qmldir b/tests/auto/qml/qmllint/data/LazyAndDirect/qmldir new file mode 100644 index 0000000000..ebc7f2a157 --- /dev/null +++ b/tests/auto/qml/qmllint/data/LazyAndDirect/qmldir @@ -0,0 +1,4 @@ +module LazyAndDirect + +Direct 1.0 Direct.qml +singleton Lazy 1.0 Lazy.qml diff --git a/tests/auto/qml/qmllint/data/Qt5Compat/GraphicalEffects/private/qmldir b/tests/auto/qml/qmllint/data/Qt5Compat/GraphicalEffects/private/qmldir new file mode 100644 index 0000000000..b13cdc9c3e --- /dev/null +++ b/tests/auto/qml/qmllint/data/Qt5Compat/GraphicalEffects/private/qmldir @@ -0,0 +1,2 @@ +module Qt5Compat.GraphicalEffects.private +typeinfo plugins.qmltypes diff --git a/tests/auto/qml/qmllint/data/Things/LintDirectly.qml b/tests/auto/qml/qmllint/data/Things/LintDirectly.qml new file mode 100644 index 0000000000..4384fa99f4 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Things/LintDirectly.qml @@ -0,0 +1,4 @@ +Pane { + property var thing: NotPartOfThings {} + property var something: Something {} +} diff --git a/tests/auto/qml/qmllint/data/Things/NotPartOfThings.qml b/tests/auto/qml/qmllint/data/Things/NotPartOfThings.qml new file mode 100644 index 0000000000..16fd397d1d --- /dev/null +++ b/tests/auto/qml/qmllint/data/Things/NotPartOfThings.qml @@ -0,0 +1,3 @@ +import QtQuick + +Component {} diff --git a/tests/auto/qml/qmllint/data/accessibleId.qml b/tests/auto/qml/qmllint/data/accessibleId.qml new file mode 100644 index 0000000000..904b856320 --- /dev/null +++ b/tests/auto/qml/qmllint/data/accessibleId.qml @@ -0,0 +1,14 @@ +import QtQml + +QtObject { + id: a + property Component c: Component { + QtObject { + id: a + property QtObject o: QtObject { + property int a: 5 + objectName: a.objectName + } + } + } +} diff --git a/tests/auto/qml/qmllint/data/animationEasing.qml b/tests/auto/qml/qmllint/data/animationEasing.qml new file mode 100644 index 0000000000..1b0c9ffea4 --- /dev/null +++ b/tests/auto/qml/qmllint/data/animationEasing.qml @@ -0,0 +1,5 @@ +import QtQml +import QtQuick +NumberAnimation { + easing.type: Easing.InOutQuad +} diff --git a/tests/auto/qml/qmllint/data/badScript.attached.qml b/tests/auto/qml/qmllint/data/badScript.attached.qml new file mode 100644 index 0000000000..f3183430fc --- /dev/null +++ b/tests/auto/qml/qmllint/data/badScript.attached.qml @@ -0,0 +1,4 @@ +import QtQuick +Text { + font.pixelSize: 10 + pointSize * 0.1 // pointSize does not exist in the scope of the binding +} diff --git a/tests/auto/qml/qmllint/data/badScriptBinding.attached.qml b/tests/auto/qml/qmllint/data/badScriptBinding.attached.qml new file mode 100644 index 0000000000..a5ec7d9050 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badScriptBinding.attached.qml @@ -0,0 +1,6 @@ +import QtQuick.Layouts +RowLayout { + function returnTrue() { return true; } + Layout.fillWidth: returnTrue() + Layout.bogusProperty: returnTrue() +} diff --git a/tests/auto/qml/qmllint/data/badScriptBinding.attachedSignalHandler.qml b/tests/auto/qml/qmllint/data/badScriptBinding.attachedSignalHandler.qml new file mode 100644 index 0000000000..56d89a81da --- /dev/null +++ b/tests/auto/qml/qmllint/data/badScriptBinding.attachedSignalHandler.qml @@ -0,0 +1,7 @@ +import QtQuick +Rectangle { + Keys.onBogusSignal: function(event) { + // the handler is good, but the signal doesn't exist + console.log(event); + } +} diff --git a/tests/auto/qml/qmllint/data/badScriptBinding.group.qml b/tests/auto/qml/qmllint/data/badScriptBinding.group.qml new file mode 100644 index 0000000000..d92feb81f0 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badScriptBinding.group.qml @@ -0,0 +1,4 @@ +import QtQuick +Text { + font.bogusProperty: "foo" + "bar" +} diff --git a/tests/auto/qml/qmllint/data/cachedDependency.qml b/tests/auto/qml/qmllint/data/cachedDependency.qml new file mode 100644 index 0000000000..5a15a66997 --- /dev/null +++ b/tests/auto/qml/qmllint/data/cachedDependency.qml @@ -0,0 +1,23 @@ +import QtQuick.Controls.impl // Caches QtQuick as depedency, without QML names +import QtQuick + +Item { + QtObject { id: object } + Item { id: item } + Rectangle { id: rectangle } + + // Various ways to cast between types contained in QtQuick and QtQml + // The QML names of both have to be available for this to work + + property QtObject objectAsObject: object as QtObject + property QtObject objectAsItem: object as Item + property QtObject objectAsRectangle: object as Rectangle + + property QtObject itemAsObject: item as QtObject + property QtObject itemAsItem: item as Item + property QtObject itemAsRectangle: item as Rectangle + + property QtObject rectangleAsObject: rectangle as QtObject + property QtObject rectangleAsItem: rectangle as Item + property QtObject rectangleAsRectangle: rectangle as Rectangle +} diff --git a/tests/auto/qml/qmllint/data/connectionNoParent.qml b/tests/auto/qml/qmllint/data/connectionNoParent.qml new file mode 100644 index 0000000000..27f7e22cf3 --- /dev/null +++ b/tests/auto/qml/qmllint/data/connectionNoParent.qml @@ -0,0 +1,5 @@ +import QtQuick + +Connections { + function onClicked() {} +} diff --git a/tests/auto/qml/qmllint/data/cycleHead.qml b/tests/auto/qml/qmllint/data/cycleHead.qml new file mode 100644 index 0000000000..080eab381f --- /dev/null +++ b/tests/auto/qml/qmllint/data/cycleHead.qml @@ -0,0 +1,7 @@ +import Cycle +import QtQuick + +Item { + property MenuItem item: a + MenuItem { id: a } +} diff --git a/tests/auto/qml/qmllint/data/goodAttachedPropertyAccess.qml b/tests/auto/qml/qmllint/data/goodAttachedPropertyAccess.qml index c46370521a..b7f64d9acb 100644 --- a/tests/auto/qml/qmllint/data/goodAttachedPropertyAccess.qml +++ b/tests/auto/qml/qmllint/data/goodAttachedPropertyAccess.qml @@ -6,6 +6,9 @@ QtObject { } Component.onCompleted: { + // NB: this currently fails as TestType.object is recognized as QtObject + // *exactly*, ignoring the QML code above and thus there's no 'progress' + // property on TestType.object console.log(TestType.object.progress); } } diff --git a/tests/auto/qml/qmllint/data/goodBindingsOnGroupAndAttached.qml b/tests/auto/qml/qmllint/data/goodBindingsOnGroupAndAttached.qml new file mode 100644 index 0000000000..7a89b82f6e --- /dev/null +++ b/tests/auto/qml/qmllint/data/goodBindingsOnGroupAndAttached.qml @@ -0,0 +1,11 @@ +import QtQuick +Rectangle { + Text { + font.pixelSize: 42 + } + + Keys.enabled: false + Keys.onPressed: function(event) { + console.log(event); + } +} diff --git a/tests/auto/qml/qmllint/data/inaccessibleId.qml b/tests/auto/qml/qmllint/data/inaccessibleId.qml new file mode 100644 index 0000000000..a3489f4741 --- /dev/null +++ b/tests/auto/qml/qmllint/data/inaccessibleId.qml @@ -0,0 +1,12 @@ +import QtQml + +QtObject { + id: a + + property Component c: Component { + QtObject { + property int a: 5 + objectName: a.objectName + } + } +} diff --git a/tests/auto/qml/qmllint/data/inaccessibleId2.qml b/tests/auto/qml/qmllint/data/inaccessibleId2.qml new file mode 100644 index 0000000000..b8f381b0b7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/inaccessibleId2.qml @@ -0,0 +1,10 @@ +import QtQml + +QtObject { + id: a + + component Handle: QtObject { + property int a: 5 + objectName: a.objectName + } +} diff --git a/tests/auto/qml/qmllint/data/invalidId1.qml b/tests/auto/qml/qmllint/data/invalidId1.qml new file mode 100644 index 0000000000..61c45530f1 --- /dev/null +++ b/tests/auto/qml/qmllint/data/invalidId1.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + id: foo.bar +} diff --git a/tests/auto/qml/qmllint/data/missingBuiltinsNoCrash.qml b/tests/auto/qml/qmllint/data/missingBuiltinsNoCrash.qml new file mode 100644 index 0000000000..a2f7d422b3 --- /dev/null +++ b/tests/auto/qml/qmllint/data/missingBuiltinsNoCrash.qml @@ -0,0 +1,3 @@ +import QtQuick // This can't be found if --bare is specified and no paths are provided + +Item {} diff --git a/tests/auto/qml/qmllint/data/missingQmltypes.qml b/tests/auto/qml/qmllint/data/missingQmltypes.qml new file mode 100644 index 0000000000..19a6dbd10b --- /dev/null +++ b/tests/auto/qml/qmllint/data/missingQmltypes.qml @@ -0,0 +1,4 @@ +import QtQml +import Qt5Compat.GraphicalEffects.private + +QtObject {} diff --git a/tests/auto/qml/qmllint/data/multiGrouped.qml b/tests/auto/qml/qmllint/data/multiGrouped.qml new file mode 100644 index 0000000000..ab6bd5bd02 --- /dev/null +++ b/tests/auto/qml/qmllint/data/multiGrouped.qml @@ -0,0 +1,6 @@ +import QtQuick + +Item { + anchors.verticalCenter: parent.verticalCenter + anchors { right: parent.left } +} diff --git a/tests/auto/qml/qmllint/data/onBindingInGroupedProperty.qml b/tests/auto/qml/qmllint/data/onBindingInGroupedProperty.qml new file mode 100644 index 0000000000..186b8a557f --- /dev/null +++ b/tests/auto/qml/qmllint/data/onBindingInGroupedProperty.qml @@ -0,0 +1,10 @@ +import QtQuick + +Rectangle +{ + id: root + border + { + ColorAnimation on color { } + } +} diff --git a/tests/auto/qml/qmllint/data/prefixedAttachedProperty.qml b/tests/auto/qml/qmllint/data/prefixedAttachedProperty.qml new file mode 100644 index 0000000000..1f9634e280 --- /dev/null +++ b/tests/auto/qml/qmllint/data/prefixedAttachedProperty.qml @@ -0,0 +1,5 @@ +import QtQuick as T + +T.Item { + T.Accessible.name: "Example" +} diff --git a/tests/auto/qml/qmllint/data/qmodelIndex.qml b/tests/auto/qml/qmllint/data/qmodelIndex.qml new file mode 100644 index 0000000000..e0df84b68b --- /dev/null +++ b/tests/auto/qml/qmllint/data/qmodelIndex.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + property ItemSelectionModel itemSelectionModel; + function row() { return itemSelectionModel.currentIndex.row; } +} diff --git a/tests/auto/qml/qmllint/data/requiredProperty.qml b/tests/auto/qml/qmllint/data/requiredProperty.qml index 6e0eec54e7..f1e82bb402 100644 --- a/tests/auto/qml/qmllint/data/requiredProperty.qml +++ b/tests/auto/qml/qmllint/data/requiredProperty.qml @@ -1,7 +1,9 @@ -import QtQml 2.15 +import QtQuick 2.15 -QtObject { - property int x - required x - x: 5 +Item { + component Required : QtObject { + property int x + required x + } + Required { x: 5 } } diff --git a/tests/auto/qml/qmllint/data/requiredPropertyInComponent.qml b/tests/auto/qml/qmllint/data/requiredPropertyInComponent.qml new file mode 100644 index 0000000000..24ecf9d706 --- /dev/null +++ b/tests/auto/qml/qmllint/data/requiredPropertyInComponent.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Row { + // explicit component + Component { + id: foo + Item { + required property int i + } + } + + // implicit component, plain property + property Component com: Item {} + + Repeater { + model: 3 + // implicit component, default property + Text { + required property int index + height: 40 + color: "black" + text: "I'm item " + index + } + } +} diff --git a/tests/auto/qml/qmllint/data/settings/bare/.qmllint.ini b/tests/auto/qml/qmllint/data/settings/bare/.qmllint.ini new file mode 100644 index 0000000000..e419c37f3a --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/bare/.qmllint.ini @@ -0,0 +1,2 @@ +[Foo] +DisableDefaultImports=true diff --git a/tests/auto/qml/qmllint/data/settings/bare/bare.qml b/tests/auto/qml/qmllint/data/settings/bare/bare.qml new file mode 100644 index 0000000000..852b8339b9 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/bare/bare.qml @@ -0,0 +1,3 @@ +import QtQuick // Should fail because Bare is specified with no import + +Item {} diff --git a/tests/auto/qml/qmllint/data/settings/qmltypes/.qmllint.ini b/tests/auto/qml/qmllint/data/settings/qmltypes/.qmllint.ini new file mode 100644 index 0000000000..95b02f2f37 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/qmltypes/.qmllint.ini @@ -0,0 +1,2 @@ +[General] +OverwriteImportTypes=custom.qmltypes diff --git a/tests/auto/qml/qmllint/data/settings/qmltypes/custom.qmltypes b/tests/auto/qml/qmllint/data/settings/qmltypes/custom.qmltypes new file mode 100644 index 0000000000..b3839652dc --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/qmltypes/custom.qmltypes @@ -0,0 +1,11 @@ +import QtQuick.tooling 1.2 +Module { + dependencies: [] + Component { + name: "Thing" + prototype: "QObject" + exports: [ + "Custom/Thing 1.0", + ] + } +} diff --git a/tests/auto/qml/qmllint/data/settings/qmltypes/qmltypes.qml b/tests/auto/qml/qmllint/data/settings/qmltypes/qmltypes.qml new file mode 100644 index 0000000000..221ddff254 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/qmltypes/qmltypes.qml @@ -0,0 +1,3 @@ +import Custom + +Thing {} diff --git a/tests/auto/qml/qmllint/data/stringAsId.qml b/tests/auto/qml/qmllint/data/stringAsId.qml new file mode 100644 index 0000000000..58ea28cb17 --- /dev/null +++ b/tests/auto/qml/qmllint/data/stringAsId.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + id: "aString" +} diff --git a/tests/auto/qml/qmllint/data/stringIdUsedInWarning.qml b/tests/auto/qml/qmllint/data/stringIdUsedInWarning.qml new file mode 100644 index 0000000000..672c00f39b --- /dev/null +++ b/tests/auto/qml/qmllint/data/stringIdUsedInWarning.qml @@ -0,0 +1,9 @@ +import QtQml + +QtObject { + id: "stringy" + property int i + property QtObject o: QtObject { + Component.onCompleted: console.log(i) + } +} diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index 79225d92de..3cdba23872 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -30,13 +30,15 @@ #include <QtTest/QtTest> #include <QProcess> #include <QString> - -#include <util.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> class TestQmllint: public QQmlDataTest { Q_OBJECT +public: + TestQmllint(); + private Q_SLOTS: void initTestCase() override; @@ -68,17 +70,27 @@ private Q_SLOTS: void settingsFile(); + void lazyAndDirect(); + + void missingBuiltinsNoCrash(); private: QString runQmllint(const QString &fileToLint, std::function<void(QProcess &)> handleResult, - const QStringList &extraArgs = QStringList(), bool ignoreSettings = true); + const QStringList &extraArgs = QStringList(), bool ignoreSettings = true, + bool addIncludeDirs = true); QString runQmllint(const QString &fileToLint, bool shouldSucceed, - const QStringList &extraArgs = QStringList(), bool ignoreSettings = true); + const QStringList &extraArgs = QStringList(), bool ignoreSettings = true, + bool addIncludeDirs = true); QString m_qmllintPath; QString m_qmljsrootgenPath; QString m_qmltyperegistrarPath; }; +TestQmllint::TestQmllint() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void TestQmllint::initTestCase() { QQmlDataTest::initTestCase(); @@ -180,7 +192,7 @@ void TestQmllint::oldQmltypes() QVERIFY(errors.contains(QStringLiteral("Warning: Found deprecated dependency specifications"))); // Checking for both lines separately so that we don't have to mess with the line endings.b - QVERIFY(errors.contains(QStringLiteral("Meta object revision and export version differ, ignoring the revision."))); + QVERIFY(errors.contains(QStringLiteral("Meta object revision and export version differ."))); QVERIFY(errors.contains(QStringLiteral("Revision 0 corresponds to version 0.0; it should be 1.0."))); } @@ -405,7 +417,7 @@ void TestQmllint::dirtyQmlCode_data() << false; QTest::newRow("nanchors1") << QStringLiteral("nanchors1.qml") - << QString() + << QString("unknown grouped property scope nanchors.") << QString() << false; QTest::newRow("nanchors2") @@ -428,6 +440,9 @@ void TestQmllint::dirtyQmlCode_data() << QString("Warning: %1:5:21: Property \"stuff\" not found on type \"Empty\"") << QString() << false; + QTest::newRow("badScriptOnAttachedProperty") + << QStringLiteral("badScript.attached.qml") + << QString("Warning: %1:3:26: Unqualified access") << QString() << false; QTest::newRow("brokenNamespace") << QStringLiteral("brokenNamespace.qml") << QString("Warning: %1:4:17: Type not found in namespace") @@ -472,6 +487,21 @@ void TestQmllint::dirtyQmlCode_data() "\"doesNotExist\" exists in the current element.") << QString() << false; + QTest::newRow("BadScriptBindingOnGroup") + << QStringLiteral("badScriptBinding.group.qml") + << QStringLiteral("Warning: %1:3:10: Binding assigned to \"bogusProperty\", but no " + "property \"bogusProperty\" exists in the current element.") + << QString() << false; + QTest::newRow("BadScriptBindingOnAttachedType") + << QStringLiteral("badScriptBinding.attached.qml") + << QStringLiteral("Warning: %1:5:12: Binding assigned to \"bogusProperty\", but no " + "property \"bogusProperty\" exists in the current element.") + << QString() << false; + QTest::newRow("BadScriptBindingOnAttachedSignalHandler") + << QStringLiteral("badScriptBinding.attachedSignalHandler.qml") + << QStringLiteral( + "Warning: %1:3:10: no matching signal found for handler \"onBogusSignal\"") + << QString() << false; QTest::newRow("BadPropertyType") << QStringLiteral("badPropertyType.qml") << QStringLiteral("No type found for property \"bad\". This may be due to a missing " @@ -590,6 +620,22 @@ void TestQmllint::dirtyQmlCode_data() << QStringLiteral("Method \"deprecatedInherited(c, d)\" is deprecated (Reason: This deprecation should be visible!)") << QString() << false; + + QTest::newRow("string as id") + << QStringLiteral("stringAsId.qml") + << QStringLiteral("ids do not need quotation marks") + << QString() + << false; + QTest::newRow("stringIdUsedInWarning") + << QStringLiteral("stringIdUsedInWarning.qml") + << QStringLiteral("Component.onCompleted: console.log(stringy.i)") + << QString() + << false; + QTest::newRow("Invalid id (expression)") + << QStringLiteral("invalidId1.qml") + << QStringLiteral("Failed to parse id") + << QString() + << false; QTest::newRow("multilineString") << QStringLiteral("multilineString.qml") << QStringLiteral("String contains unescaped line terminator which is deprecated. Use " @@ -624,6 +670,27 @@ void TestQmllint::dirtyQmlCode_data() QTest::newRow("nestedInlineComponents") << QStringLiteral("nestedInlineComponents.qml") << QStringLiteral("Nested inline components are not supported") << QString() << false; + QTest::newRow("cachedDependency") + << QStringLiteral("cachedDependency.qml") + << QStringLiteral("Unused import at %1:1:1") + << QStringLiteral("Cannot assign binding of type QQuickItem to QObject") + << true; + QTest::newRow("cycle in import") + << QStringLiteral("cycleHead.qml") + << QStringLiteral("MenuItem is part of an inheritance cycle: MenuItem -> MenuItem") + << QString() << false; + QTest::newRow("missingQmltypes") + << QStringLiteral("missingQmltypes.qml") + << QStringLiteral("QML types file does not exist") + << QString() << false; + QTest::newRow("inaccessibleId") + << QStringLiteral("inaccessibleId.qml") + << QStringLiteral("Property \"objectName\" not found on type \"int\"") + << QString() << false; + QTest::newRow("inaccessibleId2") + << QStringLiteral("inaccessibleId2.qml") + << QStringLiteral("Property \"objectName\" not found on type \"int\"") + << QString() << false; } void TestQmllint::dirtyQmlCode() @@ -640,7 +707,6 @@ void TestQmllint::dirtyQmlCode() QVERIFY(process.waitForFinished()); QCOMPARE(process.exitStatus(), QProcess::NormalExit); QEXPECT_FAIL("anchors3", "We don't see that QQuickItem cannot be assigned to QQuickAnchorLine", Abort); - QEXPECT_FAIL("nanchors1", "Invalid grouped properties are not always detected", Abort); QEXPECT_FAIL("TypePropertAccess", "We cannot discern between types and instances", Abort); QEXPECT_FAIL("badAttachedPropertyTypeString", "Script bindings do not perform property type matching", Abort); @@ -765,6 +831,17 @@ void TestQmllint::cleanQmlCode_data() QTest::newRow("CustomParserUnqualifiedAccess") << QStringLiteral("customParserUnqualifiedAccess.qml"); QTest::newRow("ImportQMLModule") << QStringLiteral("importQMLModule.qml"); + QTest::newRow("ImportDirectoryQmldir") << QStringLiteral("Things/LintDirectly.qml"); + QTest::newRow("BindingsOnGroupAndAttachedProperties") + << QStringLiteral("goodBindingsOnGroupAndAttached.qml"); + QTest::newRow("QQmlEasingEnums::Type") << QStringLiteral("animationEasing.qml"); + QTest::newRow("required property in Component") << QStringLiteral("requiredPropertyInComponent.qml"); + QTest::newRow("connectionNoParent") << QStringLiteral("connectionNoParent.qml"); // QTBUG-97600 + QTest::newRow("on binding in grouped property") << QStringLiteral("onBindingInGroupedProperty.qml"); + QTest::newRow("multipleGrouped") << QStringLiteral("multiGrouped.qml"); + QTest::newRow("ID overrides property") << QStringLiteral("accessibleId.qml"); + QTest::newRow("qmodelIndex") << QStringLiteral("qmodelIndex.qml"); + QTest::newRow("prefixedAttachedProperty") << QStringLiteral("prefixedAttachedProperty.qml"); } void TestQmllint::cleanQmlCode() @@ -776,14 +853,18 @@ void TestQmllint::cleanQmlCode() QString TestQmllint::runQmllint(const QString &fileToLint, std::function<void(QProcess &)> handleResult, - const QStringList &extraArgs, bool ignoreSettings) + const QStringList &extraArgs, bool ignoreSettings, + bool addIncludeDirs) { auto qmlImportDir = QLibraryInfo::path(QLibraryInfo::QmlImportsPath); QStringList args; - args << (QFileInfo(fileToLint).isAbsolute() ? fileToLint : testFile(fileToLint)) - << QStringLiteral("-I") << qmlImportDir - << QStringLiteral("-I") << dataDirectory(); + args << (QFileInfo(fileToLint).isAbsolute() ? fileToLint : testFile(fileToLint)); + + if (addIncludeDirs) { + args << QStringLiteral("-I") << qmlImportDir + << QStringLiteral("-I") << dataDirectory(); + } if (ignoreSettings) QStringLiteral("--ignore-settings"); @@ -815,7 +896,8 @@ QString TestQmllint::runQmllint(const QString &fileToLint, } QString TestQmllint::runQmllint(const QString &fileToLint, bool shouldSucceed, - const QStringList &extraArgs, bool ignoreSettings) + const QStringList &extraArgs, bool ignoreSettings, + bool addIncludeDirs) { return runQmllint( fileToLint, @@ -828,7 +910,7 @@ QString TestQmllint::runQmllint(const QString &fileToLint, bool shouldSucceed, else QVERIFY(process.exitCode() != 0); }, - extraArgs, ignoreSettings); + extraArgs, ignoreSettings, addIncludeDirs); } void TestQmllint::requiredProperty() @@ -869,6 +951,22 @@ void TestQmllint::settingsFile() QVERIFY(runQmllint("settings/unusedImportWarning/unused.qml", false, QStringList(), false) .contains(QStringLiteral("Warning: %1:2:1: Unused import at %1:2:1") .arg(testFile("settings/unusedImportWarning/unused.qml")))); + QVERIFY(runQmllint("settings/bare/bare.qml", false, { "--bare" }, false, false) + .contains(QStringLiteral("Failed to find the following builtins: " + "builtins.qmltypes, jsroot.qmltypes"))); + QVERIFY(runQmllint("settings/qmltypes/qmltypes.qml", true, QStringList(), false).isEmpty()); +} + +void TestQmllint::lazyAndDirect() +{ + QVERIFY(runQmllint("LazyAndDirect/Lazy.qml", true, {}, false).isEmpty()); +} + +void TestQmllint::missingBuiltinsNoCrash() +{ + QVERIFY(runQmllint("missingBuiltinsNoCrash.qml", false, { "--bare" }, false, false) + .contains(QStringLiteral("Failed to find the following builtins: " + "builtins.qmltypes, jsroot.qmltypes"))); } QTEST_MAIN(TestQmllint) diff --git a/tests/auto/qml/qmlplugindump/CMakeLists.txt b/tests/auto/qml/qmlplugindump/CMakeLists.txt index 1bf13a2c02..96eea00938 100644 --- a/tests/auto/qml/qmlplugindump/CMakeLists.txt +++ b/tests/auto/qml/qmlplugindump/CMakeLists.txt @@ -6,15 +6,13 @@ qt_internal_add_test(tst_qmlplugindump SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qmlplugindump.cpp DEFINES QT_QMLTEST_DIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::GuiPrivate Qt::Qml + Qt::QuickTestUtilsPrivate ) ## Scopes: diff --git a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp index 17e67269f3..542c1974c5 100644 --- a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp +++ b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp @@ -26,14 +26,13 @@ ** ****************************************************************************/ -#include "util.h" - #include <qtest.h> #include <QLibraryInfo> #include <QDir> #include <QProcess> #include <QDebug> #include <cstdlib> +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qmlplugindump : public QQmlDataTest { @@ -56,6 +55,7 @@ private: }; tst_qmlplugindump::tst_qmlplugindump() + : QQmlDataTest(QT_QMLTEST_DATADIR) { } diff --git a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt index dfd404575b..02a0347ac2 100644 --- a/tests/auto/qml/qmltyperegistrar/CMakeLists.txt +++ b/tests/auto/qml/qmltyperegistrar/CMakeLists.txt @@ -7,6 +7,16 @@ qt_manual_moc(moc_files OUTPUT_MOC_JSON_FILES json_list noextheader INCLUDE_DIRECTORY_TARGETS Qt::Qml) +# Dummy target to pass --private-includes to qmltyperegistrar for tst_qmltyperegistrar. +# We want to test that it expects files named foo_p.h appearing in foreign metatypes +# to be in a private/ subdirectory. In particular, we have a foreign_p.h to exercise this. +# TODO: There should be more fine grained control over this. +qt_add_library(tst_qmltyperegistrarPrivate STATIC + dummy.cpp dummy_p.h +) + +target_link_libraries(tst_qmltyperegistrarPrivate PRIVATE Qt::Core) + qt_internal_add_test(tst_qmltyperegistrar SOURCES hppheader.hpp @@ -20,6 +30,7 @@ qt_internal_add_test(tst_qmltyperegistrar # Remove: Lforeign Qt::Qml foreign + tst_qmltyperegistrarPrivate ) #### Keys ignored in scope 2:.:.:tst_qmltyperegistrar.pro:<TRUE>: @@ -36,13 +47,24 @@ qt_internal_add_test(tst_qmltyperegistrar # Simulate conditions that qt6_add_qml_module() would normally set up for us set_target_properties(tst_qmltyperegistrar PROPERTIES QT_QML_MODULE_VERSION 1.0 - QT_QML_PAST_MAJOR_VERSIONS 0 + QT_QML_MODULE_PAST_MAJOR_VERSIONS 0 QT_QML_MODULE_URI QmlTypeRegistrarTest - QT_QMLTYPES_FILENAME tst_qmltyperegistrar.qmltypes - QT_QML_MODULE_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR} + QT_QML_MODULE_TYPEINFO tst_qmltyperegistrar.qmltypes + QT_QML_MODULE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) # qt6_add_qml_module() doesn't allow us to pass through MANUAL_MOC_JSON_FILES # yet, so we have to call it directly to test that code path for now. -qt6_qml_type_registration(tst_qmltyperegistrar MANUAL_MOC_JSON_FILES ${json_list}) +_qt_internal_qml_type_registration(tst_qmltyperegistrar MANUAL_MOC_JSON_FILES ${json_list}) add_subdirectory(foreign) + +qt_add_library(tst-qmltyperegistrar-with-dashes) +target_link_libraries(tst-qmltyperegistrar-with-dashes PRIVATE Qt::Core Qt::Qml) +qt_enable_autogen_tool(tst-qmltyperegistrar-with-dashes "moc" ON) +qt_add_qml_module(tst-qmltyperegistrar-with-dashes + URI Module-With-Dashes + VERSION 1.0 + SOURCES + foo.cpp foo.h +) +qt_autogen_tools_initial_setup(tst-qmltyperegistrar-with-dashesplugin) diff --git a/tests/auto/qml/qmltyperegistrar/dummy.cpp b/tests/auto/qml/qmltyperegistrar/dummy.cpp new file mode 100644 index 0000000000..1959bc3816 --- /dev/null +++ b/tests/auto/qml/qmltyperegistrar/dummy.cpp @@ -0,0 +1,2 @@ +#include "dummy_p.h" +int foo() { return 1; } diff --git a/tests/auto/qml/qmltyperegistrar/dummy_p.h b/tests/auto/qml/qmltyperegistrar/dummy_p.h new file mode 100644 index 0000000000..e564d3b549 --- /dev/null +++ b/tests/auto/qml/qmltyperegistrar/dummy_p.h @@ -0,0 +1,2 @@ +#include <QtCore/qglobal.h> +Q_DECL_EXPORT int foo(); diff --git a/tests/auto/qml/qmltyperegistrar/foreign/CMakeLists.txt b/tests/auto/qml/qmltyperegistrar/foreign/CMakeLists.txt index ad967cdbf0..81d4b00aa3 100644 --- a/tests/auto/qml/qmltyperegistrar/foreign/CMakeLists.txt +++ b/tests/auto/qml/qmltyperegistrar/foreign/CMakeLists.txt @@ -7,7 +7,7 @@ qt_internal_add_cmake_library(foreign STATIC SOURCES - foreign.cpp foreign.h + foreign.cpp foreign.h foreign_p.h PUBLIC_LIBRARIES Qt::Core ) diff --git a/tests/auto/qml/qmltyperegistrar/foreign/foreign_p.h b/tests/auto/qml/qmltyperegistrar/foreign/foreign_p.h new file mode 100644 index 0000000000..8ea292c015 --- /dev/null +++ b/tests/auto/qml/qmltyperegistrar/foreign/foreign_p.h @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef FOREIGN_P_H +#define FOREIGN_P_H + +#include <QtCore/qobject.h> + +// qmltyperegistrar will assume this file is reachable under <private/foreign_p.h> +// It's not true, but this is how it works on actual private headers in Qt. +// See the trick in tst_qmltyperegistrar's CMakeLists.txt to turn on the --private-includes option. +class ForeignPrivate : public QObject +{ + Q_OBJECT +Q_SIGNALS: + void happens(); +}; + +#endif // FOREIGN_P_H diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp index f11f5d6404..27f83ca22f 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.cpp @@ -288,4 +288,23 @@ void tst_qmltyperegistrar::namespacesAndValueTypes() check(QMetaType::fromName("ValueTypeWithEnum2"), QMetaType::fromType<ValueTypeWithEnum2>()); } +void tst_qmltyperegistrar::derivedFromForeignPrivate() +{ + QVERIFY(qmltypesData.contains("file: \"private/foreign_p.h\"")); +} + +void tst_qmltyperegistrar::methodReturnType() +{ + QVERIFY(qmltypesData.contains("createAThing")); + QVERIFY(!qmltypesData.contains("QQmlComponent*")); + QVERIFY(qmltypesData.contains("type: \"QQmlComponent\"")); +} + +void tst_qmltyperegistrar::omitInvisible() +{ + // If it cannot resolve the type a QML_FOREIGN refers to, it should not generate anything. + QVERIFY(qmltypesData.contains( + R"(Component { file: "tst_qmltyperegistrar.h"; name: "Invisible"; accessSemantics: "none" })")); +} + QTEST_MAIN(tst_qmltyperegistrar) diff --git a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h index 2a8423c682..1372c32d02 100644 --- a/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h +++ b/tests/auto/qml/qmltyperegistrar/tst_qmltyperegistrar.h @@ -30,8 +30,10 @@ #define TST_QMLTYPEREGISTRAR_H #include "foreign.h" +#include "foreign_p.h" #include <QtQml/qqml.h> +#include <QtQml/qqmlcomponent.h> #include <QtCore/qproperty.h> #include <QtCore/qtimeline.h> #include <QtCore/qrect.h> @@ -382,6 +384,31 @@ struct BValueTypeWithEnumForeign2 QML_NAMED_ELEMENT(valueTypeWithEnum2) }; +class DerivedFromForeignPrivate : public ForeignPrivate +{ + Q_OBJECT + QML_ELEMENT +}; + +class WithMethod : public QObject +{ + Q_OBJECT + QML_ELEMENT +public: + Q_INVOKABLE QQmlComponent *createAThing(int) { return nullptr; } +}; + +class Invisible : public QObject +{ +}; + +struct InvisibleForeign +{ + Q_GADGET + QML_FOREIGN(Invisible) + QML_NAMED_ELEMENT(Invisible) +}; + class tst_qmltyperegistrar : public QObject { Q_OBJECT @@ -411,6 +438,9 @@ private slots: void finalProperty(); void parentProperty(); void namespacesAndValueTypes(); + void derivedFromForeignPrivate(); + void methodReturnType(); + void omitInvisible(); private: QByteArray qmltypesData; diff --git a/tests/auto/qml/qqmlanybinding/CMakeLists.txt b/tests/auto/qml/qqmlanybinding/CMakeLists.txt index 83c9bd7994..32efa891ea 100644 --- a/tests/auto/qml/qqmlanybinding/CMakeLists.txt +++ b/tests/auto/qml/qqmlanybinding/CMakeLists.txt @@ -10,17 +10,15 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlanybinding SOURCES - ../../shared/util.cpp ../../shared/util.h withbindable.h tst_qqmlanybinding.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::Network Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) @@ -29,7 +27,7 @@ set_target_properties(tst_qqmlanybinding PROPERTIES QT_QML_MODULE_URI bindable ) -qt6_qml_type_registration(tst_qqmlanybinding) +_qt_internal_qml_type_registration(tst_qqmlanybinding) ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qqmlanybinding/tst_qqmlanybinding.cpp b/tests/auto/qml/qqmlanybinding/tst_qqmlanybinding.cpp index b7ea29ddd3..76f8f9e89e 100644 --- a/tests/auto/qml/qqmlanybinding/tst_qqmlanybinding.cpp +++ b/tests/auto/qml/qqmlanybinding/tst_qqmlanybinding.cpp @@ -25,23 +25,31 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include "../../shared/util.h" #include <QtQml/QQmlEngine> #include <QtQml/QQmlComponent> #include <QtCore/QScopedPointer> #include <QtQml/private/qqmlanybinding_p.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> #include "withbindable.h" class tst_qqmlanybinding : public QQmlDataTest { Q_OBJECT +public: + tst_qqmlanybinding(); + private slots: void basicActions_data(); void basicActions(); void unboundQQmlPropertyBindingDoesNotCrash(); }; +tst_qqmlanybinding::tst_qqmlanybinding() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_qqmlanybinding::basicActions_data() { QTest::addColumn<QString>("fileName"); diff --git a/tests/auto/qml/qqmlanybinding/withbindable.h b/tests/auto/qml/qqmlanybinding/withbindable.h index 4488c0c350..be39d42eb7 100644 --- a/tests/auto/qml/qqmlanybinding/withbindable.h +++ b/tests/auto/qml/qqmlanybinding/withbindable.h @@ -29,6 +29,7 @@ #define WITH_BINDABLE_H #include <QObject> +#include <QtCore/qproperty.h> #include <qqml.h> class WithBinding : public QObject { diff --git a/tests/auto/qml/qqmlapplicationengine/CMakeLists.txt b/tests/auto/qml/qqmlapplicationengine/CMakeLists.txt index ea88b6c8e3..caf1e2edaa 100644 --- a/tests/auto/qml/qqmlapplicationengine/CMakeLists.txt +++ b/tests/auto/qml/qqmlapplicationengine/CMakeLists.txt @@ -12,15 +12,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlapplicationengine SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlapplicationengine.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::GuiPrivate Qt::Network Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) @@ -37,6 +35,9 @@ qt_internal_add_resource(tst_qqmlapplicationengine "tst_qqmlapplicationengine" ${tst_qqmlapplicationengine_resource_files} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmlapplicationengine) +endif() #### Keys ignored in scope 2:.:.:tst_qqmlapplicationengine.pro:<TRUE>: # TRANSLATIONS = "data/i18n/qml_ja.ts" @@ -54,3 +55,4 @@ qt_internal_extend_target(tst_qqmlapplicationengine CONDITION NOT ANDROID AND NO QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\" ) add_subdirectory(testapp) +add_subdirectory(androidassets) diff --git a/tests/auto/qml/qqmlapplicationengine/androidassets/CMakeLists.txt b/tests/auto/qml/qqmlapplicationengine/androidassets/CMakeLists.txt new file mode 100644 index 0000000000..1c0d305311 --- /dev/null +++ b/tests/auto/qml/qqmlapplicationengine/androidassets/CMakeLists.txt @@ -0,0 +1,18 @@ +qt_internal_add_test(tst_androidassets + SOURCES + tst_androidassets.cpp + PUBLIC_LIBRARIES + Qt::Gui + Qt::Qml + Qt::Quick +) + +# add qml/*.qml files as assets instead of resources + +file( + COPY qml/main.qml + DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/android-build/assets/qml/") + +file( + COPY qml/pages/MainPage.qml + DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/android-build/assets/qml/pages/") diff --git a/tests/auto/qml/qqmlapplicationengine/androidassets/qml/main.qml b/tests/auto/qml/qqmlapplicationengine/androidassets/qml/main.qml new file mode 100644 index 0000000000..6901572b00 --- /dev/null +++ b/tests/auto/qml/qqmlapplicationengine/androidassets/qml/main.qml @@ -0,0 +1,13 @@ +import QtQuick + +// relative import: has to work when loading from android assets by path or by URL +import "pages" + +Window { + width: 640 + height: 480 + visible: true + title: qsTr("Hello World") + + MainPage { } +} diff --git a/tests/auto/qml/qqmlapplicationengine/androidassets/qml/pages/MainPage.qml b/tests/auto/qml/qqmlapplicationengine/androidassets/qml/pages/MainPage.qml new file mode 100644 index 0000000000..c9549a928a --- /dev/null +++ b/tests/auto/qml/qqmlapplicationengine/androidassets/qml/pages/MainPage.qml @@ -0,0 +1,11 @@ +import QtQuick + +Rectangle { + anchors.fill: parent + color: "#ddd" + + Text { + anchors.centerIn: parent + text: "Qt 6" + } +} diff --git a/tests/auto/qml/qqmlapplicationengine/androidassets/tst_androidassets.cpp b/tests/auto/qml/qqmlapplicationengine/androidassets/tst_androidassets.cpp new file mode 100644 index 0000000000..0751e23f45 --- /dev/null +++ b/tests/auto/qml/qqmlapplicationengine/androidassets/tst_androidassets.cpp @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtQml/qqmlapplicationengine.h> +#include <QtTest/qsignalspy.h> +#include <QtTest/qtest.h> + +class tst_AndroidAssets : public QObject +{ + Q_OBJECT +private Q_SLOTS: + void loadsFromAssetsPath(); + void loadsFromAssetsUrl(); + +private: + + static QString pathPrefix() + { +#ifdef Q_OS_ANDROID + return QStringLiteral("assets:"); +#else + // Even when not running on android we can check that the copying to build dir worked. + return QCoreApplication::applicationDirPath() + QStringLiteral("/android-build/assets"); +#endif + } + + static QString urlPrefix() { +#ifdef Q_OS_ANDROID + return pathPrefix(); +#else + return QStringLiteral("file:") + pathPrefix(); +#endif + } +}; + + +void tst_AndroidAssets::loadsFromAssetsPath() +{ + QQmlApplicationEngine engine; + + // load QML file from assets, by path: + engine.load(pathPrefix() + QStringLiteral("/qml/main.qml")); + QTRY_VERIFY(engine.rootObjects().length() == 1); +} + +void tst_AndroidAssets::loadsFromAssetsUrl() +{ + QQmlApplicationEngine engine; + + // load QML file from assets, by URL: + engine.load(QUrl(urlPrefix() + QStringLiteral("/qml/main.qml"))); + QTRY_VERIFY(engine.rootObjects().length() == 1); +} + +QTEST_MAIN(tst_AndroidAssets) + +#include "tst_androidassets.moc" diff --git a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp index a35375d6f3..c948ad5b9c 100644 --- a/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp +++ b/tests/auto/qml/qqmlapplicationengine/tst_qqmlapplicationengine.cpp @@ -26,7 +26,6 @@ ** ****************************************************************************/ -#include "../../shared/util.h" #include <QQmlApplicationEngine> #include <QScopedPointer> #include <QSignalSpy> @@ -35,12 +34,13 @@ #include <QProcess> #endif #include <QDebug> +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlapplicationengine : public QQmlDataTest { Q_OBJECT public: - tst_qqmlapplicationengine() {} + tst_qqmlapplicationengine() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: @@ -101,6 +101,10 @@ void tst_qqmlapplicationengine::basicLoading() // will break. void tst_qqmlapplicationengine::testNonResolvedPath() { +#if defined(Q_OS_INTEGRITY) + QSKIP("INTEGRITY stores QML files in resources, and the path to a resource cannot be relative in this case"); +#endif + #ifdef Q_OS_ANDROID QSKIP("Android stores QML files in resources, and the path to a resource cannot be relative in this case"); #endif @@ -162,6 +166,11 @@ void tst_qqmlapplicationengine::application() #if QT_CONFIG(process) QDir::setCurrent(buildDir); QProcess *testProcess = new QProcess(this); +#ifdef Q_OS_QNX + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + env.insert("QT_FORCE_STDERR_LOGGING", "1"); // QTBUG-76546 + testProcess->setProcessEnvironment(env); +#endif QStringList args; args << qmlFile; // QML file passed as an argument is going to be run by testapp. testProcess->start(QLatin1String("testapp/testapp"), args); diff --git a/tests/auto/qml/qqmlbinding/CMakeLists.txt b/tests/auto/qml/qqmlbinding/CMakeLists.txt index 6bf1668970..78445283e4 100644 --- a/tests/auto/qml/qqmlbinding/CMakeLists.txt +++ b/tests/auto/qml/qqmlbinding/CMakeLists.txt @@ -12,17 +12,15 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlbinding SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlbinding.cpp WithBindableProperties.h - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) @@ -31,7 +29,7 @@ set_target_properties(tst_qqmlbinding PROPERTIES QT_QML_MODULE_VERSION 1.0 ) -qt6_qml_type_registration(tst_qqmlbinding) +_qt_internal_qml_type_registration(tst_qqmlbinding) ## Scopes: diff --git a/tests/auto/qml/qqmlbinding/WithBindableProperties.h b/tests/auto/qml/qqmlbinding/WithBindableProperties.h index 562b445df7..7866504495 100644 --- a/tests/auto/qml/qqmlbinding/WithBindableProperties.h +++ b/tests/auto/qml/qqmlbinding/WithBindableProperties.h @@ -30,6 +30,7 @@ #include <QObject> #include <qqml.h> +#include <QtCore/qproperty.h> class WithBindableProperties : public QObject diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp index c0c96ca6e5..328bc57447 100644 --- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp +++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp @@ -30,7 +30,7 @@ #include <QtQml/qqmlcomponent.h> #include <private/qqmlbind_p.h> #include <QtQuick/private/qquickrectangle_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include "WithBindableProperties.h" class tst_qqmlbinding : public QQmlDataTest @@ -66,6 +66,7 @@ private: }; tst_qqmlbinding::tst_qqmlbinding() + : QQmlDataTest(QT_QMLTEST_DATADIR) { } @@ -377,6 +378,10 @@ void tst_qqmlbinding::disabledOnReadonlyProperty() void tst_qqmlbinding::delayed() { +#ifdef Q_OS_ANDROID + QSKIP("This test crashes on Android. QTBUG-103310"); +#endif + QQmlEngine engine; QQmlComponent c(&engine, testFileUrl("delayed.qml")); QScopedPointer<QQuickItem> item {qobject_cast<QQuickItem*>(c.create())}; diff --git a/tests/auto/qml/qqmlchangeset/CMakeLists.txt b/tests/auto/qml/qqmlchangeset/CMakeLists.txt index da06b85fad..510e304717 100644 --- a/tests/auto/qml/qqmlchangeset/CMakeLists.txt +++ b/tests/auto/qml/qqmlchangeset/CMakeLists.txt @@ -1,10 +1,10 @@ # Generated from qqmlchangeset.pro. ##################################################################### -## tst_qqmlhangeset Test: +## tst_qqmlchangeset Test: ##################################################################### -qt_internal_add_test(tst_qqmlhangeset +qt_internal_add_test(tst_qqmlchangeset SOURCES tst_qqmlchangeset.cpp PUBLIC_LIBRARIES diff --git a/tests/auto/qml/qqmlcomponent/CMakeLists.txt b/tests/auto/qml/qqmlcomponent/CMakeLists.txt index c7dd50e8d6..7ef68135c9 100644 --- a/tests/auto/qml/qqmlcomponent/CMakeLists.txt +++ b/tests/auto/qml/qqmlcomponent/CMakeLists.txt @@ -12,11 +12,7 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlcomponent SOURCES - ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h - ../../shared/util.cpp ../../shared/util.h tst_qqmlcomponent.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui @@ -24,6 +20,7 @@ qt_internal_add_test(tst_qqmlcomponent Qt::Network Qt::QmlPrivate Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlcomponent/data/RequiredPropertiesInAttached.qml b/tests/auto/qml/qqmlcomponent/data/RequiredPropertiesInAttached.qml new file mode 100644 index 0000000000..ac496b6131 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/RequiredPropertiesInAttached.qml @@ -0,0 +1,6 @@ +import qt.test 1.0 +import QtQml +QtObject { + AttachedRequiredProperty.index: -1 + AttachedRequiredProperty.name: "minus one" +} // error: we don't support required attached properties diff --git a/tests/auto/qml/qqmlcomponent/data/RequiredPropertiesInGroup.qml b/tests/auto/qml/qqmlcomponent/data/RequiredPropertiesInGroup.qml new file mode 100644 index 0000000000..786a293647 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/RequiredPropertiesInGroup.qml @@ -0,0 +1,5 @@ +import qt.test 1.0 +GroupedRequiredProperty { + group.index: 42 + group.name: "foobar" +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetInSameFile.qml b/tests/auto/qml/qqmlcomponent/data/RequiredSetInSameFile.qml index 76dfcd87e5..76dfcd87e5 100644 --- a/tests/auto/qml/qqmlcomponent/data/requiredSetInSameFile.qml +++ b/tests/auto/qml/qqmlcomponent/data/RequiredSetInSameFile.qml diff --git a/tests/auto/qml/qqmlcomponent/data/RequiredTwoPropertiesSet.qml b/tests/auto/qml/qqmlcomponent/data/RequiredTwoPropertiesSet.qml new file mode 100644 index 0000000000..a925303403 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/RequiredTwoPropertiesSet.qml @@ -0,0 +1,6 @@ +import qt.test 1.0 +TwoRequiredProperties { + id: test + index: 1 + name: "foobar" +} diff --git a/tests/auto/qml/qqmlcomponent/data/RerequiredNotSet.qml b/tests/auto/qml/qqmlcomponent/data/RerequiredNotSet.qml new file mode 100644 index 0000000000..2dd33e8196 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/RerequiredNotSet.qml @@ -0,0 +1,3 @@ +RequiredSetInSameFile { + required i +} // error: we explicitly want required here, but it's not set diff --git a/tests/auto/qml/qqmlcomponent/data/jsmodule/module.mjs b/tests/auto/qml/qqmlcomponent/data/jsmodule/module.mjs index 3dd3507d45..9175ba0a67 100644 --- a/tests/auto/qml/qqmlcomponent/data/jsmodule/module.mjs +++ b/tests/auto/qml/qqmlcomponent/data/jsmodule/module.mjs @@ -1,5 +1,6 @@ export function withProp(root) { - const component = Qt.createComponent("data/jsmodule/Dynamic.qml"); + const prefix = Qt.platform.os == "android" ? "qrc:" : ""; + const component = Qt.createComponent(prefix + "data/jsmodule/Dynamic.qml"); const el = component.createObject(root, { value: 42 }); return el.value; } diff --git a/tests/auto/qml/qqmlcomponent/data/requiredChildOfBadBase.qml b/tests/auto/qml/qqmlcomponent/data/requiredChildOfBadBase.qml new file mode 100644 index 0000000000..b75f06d5d3 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredChildOfBadBase.qml @@ -0,0 +1 @@ +BaseWithRequired {} // fails as required property not set diff --git a/tests/auto/qml/qqmlcomponent/data/requiredChildOfGoodBase.qml b/tests/auto/qml/qqmlcomponent/data/requiredChildOfGoodBase.qml new file mode 100644 index 0000000000..31d2d3065b --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredChildOfGoodBase.qml @@ -0,0 +1 @@ +RequiredSetInSameFile {} // succeeds as required property is set diff --git a/tests/auto/qml/qqmlcomponent/data/requiredGroup.bad.qml b/tests/auto/qml/qqmlcomponent/data/requiredGroup.bad.qml new file mode 100644 index 0000000000..744c9131dc --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredGroup.bad.qml @@ -0,0 +1,3 @@ +import qt.test 1.0 +RequiredGroup { +} // error: required group property is not set diff --git a/tests/auto/qml/qqmlcomponent/data/requiredGroup.good.qml b/tests/auto/qml/qqmlcomponent/data/requiredGroup.good.qml new file mode 100644 index 0000000000..836b4c6968 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredGroup.good.qml @@ -0,0 +1,4 @@ +import qt.test 1.0 +RequiredGroup { + group.disabled.buttonText: "salmon" +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInAttached.bad.qml b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInAttached.bad.qml new file mode 100644 index 0000000000..6a55a06688 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInAttached.bad.qml @@ -0,0 +1,7 @@ +import qt.test 1.0 +import QtQml +QtObject { + AttachedRequiredProperty.onIndexChanged: { + var s = "this is just to trigger the attachment" + } +} // error: we don't support required attached properties diff --git a/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInAttached.bad2.qml b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInAttached.bad2.qml new file mode 100644 index 0000000000..5ae49fd26a --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInAttached.bad2.qml @@ -0,0 +1,5 @@ +import qt.test 1.0 +import QtQml +QtObject { + AttachedRequiredProperty.index: -1 +} // error: we don't support required attached properties diff --git a/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInAttachedIndirect.qml b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInAttachedIndirect.qml new file mode 100644 index 0000000000..5993845cef --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInAttachedIndirect.qml @@ -0,0 +1,4 @@ +import qt.test 1.0 +RequiredPropertiesInAttached { + AttachedRequiredProperty.index: -1 +} // error: we don't support required attached properties diff --git a/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInGroup.bad.qml b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInGroup.bad.qml new file mode 100644 index 0000000000..7a3364f056 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInGroup.bad.qml @@ -0,0 +1,2 @@ +import qt.test 1.0 +GroupedRequiredProperty {} // error (required properties not set) diff --git a/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInGroup.bad2.qml b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInGroup.bad2.qml new file mode 100644 index 0000000000..cde4278a71 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInGroup.bad2.qml @@ -0,0 +1,5 @@ +import qt.test 1.0 +GroupedRequiredProperty { + group.index: 42 + // error (group.name is not set) +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInGroupIndirect.qml b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInGroupIndirect.qml new file mode 100644 index 0000000000..71e66ff3a7 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredPropertiesInGroupIndirect.qml @@ -0,0 +1,5 @@ +import qt.test 1.0 +RequiredPropertiesInGroup { + group.index: 44 + // should succeed as there's a binding on group.name in the base type +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponent.bad.qml b/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponent.bad.qml new file mode 100644 index 0000000000..9954dd5813 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponent.bad.qml @@ -0,0 +1,8 @@ +import QtQuick +Item { + component RequiredPropertyType : QtObject { + required property int i + } + + RequiredPropertyType {} // should fail +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponent.good.qml b/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponent.good.qml new file mode 100644 index 0000000000..29506b7dd4 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponent.good.qml @@ -0,0 +1,9 @@ +import QtQuick +Item { + component RequiredPropertyType : QtObject { + required property int i + i: 42 + } + + RequiredPropertyType {} // should succeed +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponentWithCppBase.bad.qml b/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponentWithCppBase.bad.qml new file mode 100644 index 0000000000..8a83d8979c --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponentWithCppBase.bad.qml @@ -0,0 +1,9 @@ +import QtQuick +import qt.test 1.0 +Item { + component RequiredPropertyType : TwoRequiredProperties { + index: 0 + // but name is unset + } + RequiredPropertyType {} // should fail (name is not initialized) +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponentWithCppBase.good.qml b/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponentWithCppBase.good.qml new file mode 100644 index 0000000000..3e99554ffd --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponentWithCppBase.good.qml @@ -0,0 +1,9 @@ +import QtQuick +import qt.test 1.0 +Item { + component RequiredPropertyType : TwoRequiredProperties { + index: 11 + name: "foobar" + } + RequiredPropertyType {} // should succeed +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponentWithIndirectCppBase.qml b/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponentWithIndirectCppBase.qml new file mode 100644 index 0000000000..294a9f0172 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredPropertyInlineComponentWithIndirectCppBase.qml @@ -0,0 +1,6 @@ +import QtQuick +import qt.test 1.0 +Item { + component RequiredPropertyType : RequiredTwoPropertiesSet { } + RequiredPropertyType {} // should succeed +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredSetLater.rerequired.qml b/tests/auto/qml/qqmlcomponent/data/requiredSetLater.rerequired.qml new file mode 100644 index 0000000000..975f797a20 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredSetLater.rerequired.qml @@ -0,0 +1,3 @@ +RerequiredNotSet { + i: 43 +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredTwoProperties.qml b/tests/auto/qml/qqmlcomponent/data/requiredTwoProperties.qml new file mode 100644 index 0000000000..10ce79de33 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredTwoProperties.qml @@ -0,0 +1,5 @@ +import qt.test 1.0 +TwoRequiredProperties { + id: test + index: 1 // this property is fine +} diff --git a/tests/auto/qml/qqmlcomponent/data/requiredTwoPropertiesDummy.qml b/tests/auto/qml/qqmlcomponent/data/requiredTwoPropertiesDummy.qml new file mode 100644 index 0000000000..4e084fabd6 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/requiredTwoPropertiesDummy.qml @@ -0,0 +1 @@ +RequiredTwoPropertiesSet {} // no error is expected diff --git a/tests/auto/qml/qqmlcomponent/data/rerequiredSet.qml b/tests/auto/qml/qqmlcomponent/data/rerequiredSet.qml new file mode 100644 index 0000000000..316d5b3f4b --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/rerequiredSet.qml @@ -0,0 +1,4 @@ +RequiredSetInSameFile { + required i + i: 43 +} diff --git a/tests/auto/qml/qqmlcomponent/data/rerequiredSetLater.qml b/tests/auto/qml/qqmlcomponent/data/rerequiredSetLater.qml new file mode 100644 index 0000000000..4e31431095 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/rerequiredSetLater.qml @@ -0,0 +1,4 @@ +RerequiredNotSet { + required i + i: 43 +} // note: even though parent type is borked, this type is fine diff --git a/tests/auto/qml/qqmlcomponent/data/shadowingFromCpp.qml b/tests/auto/qml/qqmlcomponent/data/shadowingFromCpp.qml new file mode 100644 index 0000000000..01d9c27e03 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/shadowingFromCpp.qml @@ -0,0 +1,5 @@ +import qt.test 1.0 +ShadowedRequiredProperty { + id: test + index: 1 // this property is fine +} diff --git a/tests/auto/qml/qqmlcomponent/data/shadowingFromQmlChild.qml b/tests/auto/qml/qqmlcomponent/data/shadowingFromQmlChild.qml new file mode 100644 index 0000000000..111c5580b8 --- /dev/null +++ b/tests/auto/qml/qqmlcomponent/data/shadowingFromQmlChild.qml @@ -0,0 +1,6 @@ +import qt.test 1.0 +TwoRequiredProperties { + id: test + index: 1 // this property is fine + property string name: "overwritten and not required" +} diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index a1ee52554b..decbe7dd22 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -35,13 +35,14 @@ #include <QtQuick> #include <QtQuick/private/qquickrectangle_p.h> #include <QtQuick/private/qquickmousearea_p.h> +#include <QtQuick/private/qquickpalette_p.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> +#include <QtQuickTestUtils/private/testhttpserver_p.h> #include <private/qqmlguardedcontextdata_p.h> #include <private/qv4qmlcontext_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4qmlcontext_p.h> #include <qcolor.h> -#include "../../shared/util.h" -#include "testhttpserver.h" #include <algorithm> @@ -98,7 +99,7 @@ class tst_qqmlcomponent : public QQmlDataTest { Q_OBJECT public: - tst_qqmlcomponent() { engine.setIncubationController(&ic); } + tst_qqmlcomponent() : QQmlDataTest(QT_QMLTEST_DATADIR) { engine.setIncubationController(&ic); } private slots: void null(); @@ -686,20 +687,117 @@ private: QQuickItem *m_defaultProperty = nullptr; }; +class TwoRequiredProperties : public QObject +{ + Q_OBJECT + Q_PROPERTY(int index READ index WRITE setIndex NOTIFY indexChanged REQUIRED) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged REQUIRED) + + int m_index = 0; + QString m_name; + +public: + TwoRequiredProperties(QObject *parent = nullptr) : QObject(parent) { } + + int index() const { return m_index; } + QString name() const { return m_name; } + + void setIndex(int x) + { + if (m_index == x) + return; + m_index = x; + Q_EMIT indexChanged(); + } + void setName(const QString &x) + { + if (m_name == x) + return; + m_name = x; + Q_EMIT nameChanged(); + } + +Q_SIGNALS: + void indexChanged(); + void nameChanged(); +}; + +class ShadowedRequiredProperty : public TwoRequiredProperties +{ + Q_OBJECT + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged /* REQUIRED */) + // Note: should be able to take methods from the base class +}; + +class AttachedRequiredProperties : public QObject +{ + Q_OBJECT + QML_ATTACHED(TwoRequiredProperties) +public: + AttachedRequiredProperties(QObject *parent = nullptr) : QObject(parent) { } + static TwoRequiredProperties *qmlAttachedProperties(QObject *parent) + { + return new TwoRequiredProperties(parent); + } +}; + +class GroupedRequiredProperties : public QObject +{ + Q_OBJECT + Q_PROPERTY(TwoRequiredProperties *group READ group) + TwoRequiredProperties m_group; + +public: + GroupedRequiredProperties(QObject *parent = nullptr) : QObject(parent) { } + TwoRequiredProperties *group() { return &m_group; } +}; + +class RequiredGroup : public QObject +{ + Q_OBJECT + // use QQuickPalette not to create an extra test-only + Q_PROPERTY(QQuickPalette *group READ group REQUIRED) + QQuickPalette m_group; + +public: + RequiredGroup(QObject *parent = nullptr) : QObject(parent) { } + QQuickPalette *group() { return &m_group; } +}; + void tst_qqmlcomponent::testRequiredProperties_data() { qmlRegisterType<RequiredDefaultCpp>("qt.test", 1, 0, "RequiredDefaultCpp"); + qmlRegisterType<TwoRequiredProperties>("qt.test", 1, 0, "TwoRequiredProperties"); + qmlRegisterType<ShadowedRequiredProperty>("qt.test", 1, 0, "ShadowedRequiredProperty"); + qmlRegisterUncreatableType<AttachedRequiredProperties>( + "qt.test", 1, 0, "AttachedRequiredProperty", + tr("AttachedRequiredProperties is an attached property")); + qmlRegisterType<GroupedRequiredProperties>("qt.test", 1, 0, "GroupedRequiredProperty"); + qmlRegisterType<RequiredGroup>("qt.test", 1, 0, "RequiredGroup"); + QTest::addColumn<QUrl>("testFile"); QTest::addColumn<bool>("shouldSucceed"); QTest::addColumn<QString>("errorMsg"); QTest::addRow("requiredSetViaChainedAlias") << testFileUrl("requiredSetViaChainedAlias.qml") << true << ""; QTest::addRow("requiredNotSet") << testFileUrl("requiredNotSet.qml") << false << "Required property i was not initialized"; - QTest::addRow("requiredSetInSameFile") << testFileUrl("requiredSetInSameFile.qml") << true << ""; + QTest::addRow("requiredSetInSameFile") << testFileUrl("RequiredSetInSameFile.qml") << true << ""; QTest::addRow("requiredSetViaAlias1") << testFileUrl("requiredSetViaAliasBeforeSameFile.qml") << true << ""; QTest::addRow("requiredSetViaAlias2") << testFileUrl("requiredSetViaAliasAfterSameFile.qml") << true << ""; QTest::addRow("requiredSetViaAlias3") << testFileUrl("requiredSetViaAliasParentFile.qml") << true << ""; + QTest::addRow("requiredSetInBase") << testFileUrl("requiredChildOfGoodBase.qml") << true << ""; + QTest::addRow("requiredNotSetInBase") << testFileUrl("requiredChildOfBadBase.qml") << false << "Required property i was not initialized"; + QTest::addRow("rerequiredSet") << testFileUrl("rerequiredSet.qml") << true << ""; + QTest::addRow("rerequiredNotSet") << testFileUrl("RerequiredNotSet.qml") << false + << "Required property i was not initialized"; + QTest::addRow("requiredSetLater(rerequired)") + << testFileUrl("requiredSetLater.rerequired.qml") << true << ""; + QTest::addRow("rerequiredSetLater") << testFileUrl("rerequiredSetLater.qml") << true << ""; QTest::addRow("shadowing") << testFileUrl("shadowing.qml") << false << "Required property i was not initialized"; + QTest::addRow("shadowing (C++)") << testFileUrl("shadowingFromCpp.qml") << false + << "Required property name was not initialized"; + QTest::addRow("shadowing (C++ indirect)") << testFileUrl("shadowingFromQmlChild.qml") << false + << "Required property name was not initialized"; QTest::addRow("setLater") << testFileUrl("requiredSetLater.qml") << true << ""; QTest::addRow("setViaAliasToSubcomponent") << testFileUrl("setViaAliasToSubcomponent.qml") << true << ""; QTest::addRow("aliasToSubcomponentNotSet") << testFileUrl("aliasToSubcomponentNotSet.qml") << false << "It can be set via the alias property i_alias"; @@ -707,9 +805,55 @@ void tst_qqmlcomponent::testRequiredProperties_data() QTest::addRow("required default not set") << testFileUrl("requiredDefault.2.qml") << false << "Required property requiredDefault was not initialized"; QTest::addRow("required default set (C++)") << testFileUrl("requiredDefault.3.qml") << true << ""; QTest::addRow("required default not set (C++)") << testFileUrl("requiredDefault.4.qml") << false << "Required property defaultProperty was not initialized"; + // QTBUG-96200: + QTest::addRow("required two set one (C++)") << testFileUrl("requiredTwoProperties.qml") << false + << "Required property name was not initialized"; + QTest::addRow("required two set two (C++)") + << testFileUrl("RequiredTwoPropertiesSet.qml") << true << ""; + QTest::addRow("required two set two (C++ indirect)") + << testFileUrl("requiredTwoPropertiesDummy.qml") << true << ""; + + QTest::addRow("required set (inline component)") + << testFileUrl("requiredPropertyInlineComponent.good.qml") << true << ""; + QTest::addRow("required not set (inline component)") + << testFileUrl("requiredPropertyInlineComponent.bad.qml") << false + << "Required property i was not initialized"; + QTest::addRow("required set (inline component, C++)") + << testFileUrl("requiredPropertyInlineComponentWithCppBase.good.qml") << true << ""; + QTest::addRow("required not set (inline component, C++)") + << testFileUrl("requiredPropertyInlineComponentWithCppBase.bad.qml") << false + << "Required property name was not initialized"; + QTest::addRow("required set (inline component, C++ indirect)") + << testFileUrl("requiredPropertyInlineComponentWithIndirectCppBase.qml") << true << ""; + QTest::addRow("required not set (attached)") + << testFileUrl("requiredPropertiesInAttached.bad.qml") << false + << "Attached property has required properties. This is not supported"; + QTest::addRow("required two set one (attached)") + << testFileUrl("requiredPropertiesInAttached.bad2.qml") << false + << "Attached property has required properties. This is not supported"; + QTest::addRow("required two set two (attached)") + << testFileUrl("RequiredPropertiesInAttached.qml") << false + << "Attached property has required properties. This is not supported"; + QTest::addRow("required two set two (attached indirect)") + << testFileUrl("requiredPropertiesInAttachedIndirect.qml") << false + << "Attached property has required properties. This is not supported"; + QTest::addRow("required itself not set (group)") + << testFileUrl("requiredGroup.bad.qml") << false + << "Required property group was not initialized"; + QTest::addRow("required itself set (group)") + << testFileUrl("requiredGroup.good.qml") << true << ""; + QTest::addRow("required not set (group)") + << testFileUrl("requiredPropertiesInGroup.bad.qml") << false + << "Required property index was not initialized"; + QTest::addRow("required two set one (group)") + << testFileUrl("requiredPropertiesInGroup.bad2.qml") << false + << "Required property name was not initialized"; + QTest::addRow("required two set two (group)") + << testFileUrl("RequiredPropertiesInGroup.qml") << true << ""; + QTest::addRow("required two set two (group indirect)") + << testFileUrl("requiredPropertiesInGroupIndirect.qml") << true << ""; } - void tst_qqmlcomponent::testRequiredProperties() { QQmlEngine eng; @@ -719,10 +863,18 @@ void tst_qqmlcomponent::testRequiredProperties() QQmlComponent comp(&eng); comp.loadUrl(testFile); QScopedObjPointer obj {comp.create()}; + QEXPECT_FAIL("required not set (group)", + "We fail to recognize required sub-properties inside a group property when that " + "group property is unused (QTBUG-96544)", + Abort); + QEXPECT_FAIL("required two set one (group)", + "We fail to recognized required sub-properties inside a group property, even when " + "that group property is used (QTBUG-96544)", + Abort); if (shouldSucceed) QVERIFY(obj); else { - QVERIFY(!obj); + QVERIFY2(!obj, "The object is valid when it shouldn't be"); QFETCH(QString, errorMsg); QVERIFY(comp.errorString().contains(errorMsg)); } diff --git a/tests/auto/qml/qqmlconnections/CMakeLists.txt b/tests/auto/qml/qqmlconnections/CMakeLists.txt index fef16f58f8..3761017b60 100644 --- a/tests/auto/qml/qqmlconnections/CMakeLists.txt +++ b/tests/auto/qml/qqmlconnections/CMakeLists.txt @@ -12,16 +12,14 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlconnections SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlconnections.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlconnections/data/invalidTarget.qml b/tests/auto/qml/qqmlconnections/data/invalidTarget.qml new file mode 100644 index 0000000000..23599649ec --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/invalidTarget.qml @@ -0,0 +1,31 @@ +import QtQml + +QtObject { + id: root + objectName: button.objectName + + property QtObject b: QtObject { + objectName: "button" + id: button + signal clicked + } + + property Connections c: Connections { + id: connections + target: null + function onClicked() { button.destroy(); } + } + + property Timer t: Timer { + interval: 10 + running: true + onTriggered: { + root.objectName = connections.target.objectName + } + } + + Component.onCompleted: { + connections.target = button; + button.clicked() + } +} diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp index 31f000fab6..a28a8dd9dd 100644 --- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp +++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp @@ -30,8 +30,8 @@ #include <QtQml/qqmlcomponent.h> #include <private/qqmlconnections_p.h> #include <private/qquickitem_p.h> -#include "../../shared/util.h" #include <QtQml/qqmlscriptstring.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlconnections : public QQmlDataTest { @@ -78,6 +78,7 @@ private slots: void noAcceleratedGlobalLookup(); void bindToPropertyWithUnderscoreChangeHandler(); + void invalidTarget(); private: QQmlEngine engine; @@ -85,6 +86,7 @@ private: }; tst_qqmlconnections::tst_qqmlconnections() + : QQmlDataTest(QT_QMLTEST_DATADIR) { } @@ -489,6 +491,25 @@ void tst_qqmlconnections::bindToPropertyWithUnderscoreChangeHandler() QVERIFY(root->property("success").toBool()); } +void tst_qqmlconnections::invalidTarget() +{ + QQmlEngine engine; + const QUrl url = testFileUrl("invalidTarget.qml"); + QQmlComponent component(&engine, url); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + + QScopedPointer<QObject> root {component.create()}; + QVERIFY(root); + QCOMPARE(root->objectName(), QStringLiteral("button")); + + QTest::ignoreMessage( + QtWarningMsg, + qPrintable( + url.toString() + + QLatin1String(":5:5: TypeError: Cannot read property 'objectName' of null"))); + QTRY_VERIFY(root->objectName().isEmpty()); +} + QTEST_MAIN(tst_qqmlconnections) #include "tst_qqmlconnections.moc" diff --git a/tests/auto/qml/qqmlconsole/CMakeLists.txt b/tests/auto/qml/qqmlconsole/CMakeLists.txt index 5e98ed2f31..5096503c15 100644 --- a/tests/auto/qml/qqmlconsole/CMakeLists.txt +++ b/tests/auto/qml/qqmlconsole/CMakeLists.txt @@ -12,17 +12,19 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlconsole SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlconsole.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::GuiPrivate Qt::Qml + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmlconsole) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qqmlconsole/data/assert.qml b/tests/auto/qml/qqmlconsole/data/assert.qml index dd580e2a72..9687437c48 100644 --- a/tests/auto/qml/qqmlconsole/data/assert.qml +++ b/tests/auto/qml/qqmlconsole/data/assert.qml @@ -29,21 +29,22 @@ import QtQuick 2.0 QtObject { - property int q:1 + property int q: 1 + function assertFail() { - console.assert(0, "This will fail too") + console.assert(0, "This will fail too"); } Component.onCompleted: { - var x = 12; + const x = 12; console.assert(x == 12, "This will pass"); try { - console.assert(x < 12, "This will fail"); + console.assert(x < 12, "This will fail"); } catch (e) { console.log(e); } - console.assert("x < 12", "This will pass too") + console.assert("x < 12", "This will pass too"); assertFail(); - console.assert(1) + console.assert(1); } } diff --git a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml index d593f0dfa1..6d471e7f80 100644 --- a/tests/auto/qml/qqmlconsole/data/categorized_logging.qml +++ b/tests/auto/qml/qqmlconsole/data/categorized_logging.qml @@ -40,7 +40,7 @@ import QtQuick 2.12 Item { - id:root + id: root LoggingCategory { id: testCategory @@ -69,8 +69,11 @@ Item { console.warn(testCategoryStartingFromWarning, "console.warn"); console.error(testCategoryStartingFromWarning, "console.error"); - testCategory.name = "qt.test2"; - testCategory.defaultLogLevel = LoggingCategory.Debug; + testCategory.name = "qt.test"; // should be silent + testCategoryStartingFromWarning.name = "qt.test.other"; // should issue a warning + + testCategory.defaultLogLevel = LoggingCategory.Debug; // should be silent + testCategoryStartingFromWarning.defaultLogLevel = LoggingCategory.Debug; // should issue a warning console.error(emptyCategory, "console.error"); } diff --git a/tests/auto/qml/qqmlconsole/data/exception.qml b/tests/auto/qml/qqmlconsole/data/exception.qml index 63afd18828..b9b83525e8 100644 --- a/tests/auto/qml/qqmlconsole/data/exception.qml +++ b/tests/auto/qml/qqmlconsole/data/exception.qml @@ -30,12 +30,12 @@ import QtQuick 2.0 QtObject { function exceptionFail() { - console.exception("Exception 2") + console.exception("Exception 2"); } Component.onCompleted: { try { - console.exception("Exception 1") + console.exception("Exception 1"); } catch (e) { console.log(e); } diff --git a/tests/auto/qml/qqmlconsole/data/logging.qml b/tests/auto/qml/qqmlconsole/data/logging.qml index f5eaeb442a..ac3884bc8e 100644 --- a/tests/auto/qml/qqmlconsole/data/logging.qml +++ b/tests/auto/qml/qqmlconsole/data/logging.qml @@ -30,7 +30,8 @@ import QtQuick 2.0 QtObject { - id:root + id: root + required property var customObject required property var stringListProperty @@ -49,14 +50,14 @@ QtObject { consoleCount(); consoleCount(); - var a = [1, 2]; - var b = {a: "hello", d: 1 }; - b.toString = function() { return JSON.stringify(b) } - var c - var d = 12; - var e = function() { return 5;}; - var f = true; - var g = {toString: function() { throw new Error('toString'); }}; + const a = [1, 2]; + const b = { a: "hello", d: 1 }; + b.toString = function() { return JSON.stringify(b); } + let c; + const d = 12; + const e = function() { return 5; }; + const f = true; + const g = { toString: function() { throw new Error('toString'); } }; console.log(a); console.log(b); @@ -79,6 +80,6 @@ QtObject { return; } - throw ("console.log(exception) should have raised an exception"); + throw "console.log(exception) should have raised an exception"; } } diff --git a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp index 666c97a07f..019be5f16a 100644 --- a/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp +++ b/tests/auto/qml/qqmlconsole/tst_qqmlconsole.cpp @@ -31,13 +31,13 @@ #include <QQmlComponent> #include <QQmlContext> #include <QLoggingCategory> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlconsole : public QQmlDataTest { Q_OBJECT public: - tst_qqmlconsole() {} + tst_qqmlconsole() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void logging(); @@ -133,18 +133,27 @@ void tst_qqmlconsole::categorized_logging() QVERIFY(messageHandler.messages().contains("qt.test.warning: console.error")); QString emptyCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(56).arg(5) + - "QML LoggingCategory: Declaring the name of the LoggingCategory is mandatory and cannot be changed later !"; + "QML LoggingCategory: Declaring the name of a LoggingCategory is mandatory and cannot be changed later"; QVERIFY(messageHandler.messages().contains(emptyCategory)); - QString changedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + - "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the Item is created"; + + QString notChangedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + + "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the component is completed"; + QVERIFY(!messageHandler.messages().contains(notChangedCategory)); + QString changedCategory = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) + + "QML LoggingCategory: The name of a LoggingCategory cannot be changed after the component is completed"; QVERIFY(messageHandler.messages().contains(changedCategory)); - QString changedDefaultLogLevel = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + - "QML LoggingCategory: The defaultLogLevel of a LoggingCategory cannot be changed after the Item is created"; + + QString notChangedDefaultLogLevel = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(45).arg(5) + + "QML LoggingCategory: The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed"; + QVERIFY(!messageHandler.messages().contains(notChangedDefaultLogLevel)); + QString changedDefaultLogLevel = "default: " + QString::fromLatin1("%1:%2:%3: ").arg(testUrl.toString()).arg(50).arg(5) + + "QML LoggingCategory: The defaultLogLevel of a LoggingCategory cannot be changed after the component is completed"; QVERIFY(messageHandler.messages().contains(changedDefaultLogLevel)); - QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(75) + + + QString useEmptyCategory = "default: " + QString::fromLatin1("%1:%2: ").arg(testUrl.toString()).arg(78) + "Error: A QmlLoggingCatgory was provided without a valid name"; QVERIFY(messageHandler.messages().contains(useEmptyCategory)); @@ -190,13 +199,13 @@ void tst_qqmlconsole::testAssert() QString assert1 = "This will fail\n" + QString::fromLatin1("expression for onCompleted (%1:%2)") .arg(testUrl.toString()) - .arg(41); + .arg(42); QString assert2 = "This will fail too\n" - + QString::fromLatin1("assertFail (%1:%2)\n").arg(testUrl.toString()).arg(34) + + QString::fromLatin1("assertFail (%1:%2)\n").arg(testUrl.toString()).arg(35) + QString::fromLatin1("expression for onCompleted (%1:%2)") .arg(testUrl.toString()) - .arg(46); + .arg(47); QTest::ignoreMessage(QtCriticalMsg, qPrintable(assert1)); QTest::ignoreMessage(QtCriticalMsg, qPrintable(assert2)); diff --git a/tests/auto/qml/qqmlcontext/CMakeLists.txt b/tests/auto/qml/qqmlcontext/CMakeLists.txt index ce07e8c785..5b2c4e7a5b 100644 --- a/tests/auto/qml/qqmlcontext/CMakeLists.txt +++ b/tests/auto/qml/qqmlcontext/CMakeLists.txt @@ -12,15 +12,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlcontext SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlcontext.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index 4a850541a6..e586604862 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -37,13 +37,13 @@ #include <private/qqmlguardedcontextdata_p.h> #include <private/qv4qmlcontext_p.h> #include <private/qv4object_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlcontext : public QQmlDataTest { Q_OBJECT public: - tst_qqmlcontext() {} + tst_qqmlcontext() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void baseUrl(); diff --git a/tests/auto/qml/qqmldelegatemodel/CMakeLists.txt b/tests/auto/qml/qqmldelegatemodel/CMakeLists.txt index 9020d9e892..3cbb4540e0 100644 --- a/tests/auto/qml/qqmldelegatemodel/CMakeLists.txt +++ b/tests/auto/qml/qqmldelegatemodel/CMakeLists.txt @@ -12,10 +12,7 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmldelegatemodel SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmldelegatemodel.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui @@ -23,6 +20,7 @@ qt_internal_add_test(tst_qqmldelegatemodel Qt::QmlModelsPrivate Qt::QmlPrivate Qt::Quick + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmldelegatemodel/data/redrawUponColumnChange.qml b/tests/auto/qml/qqmldelegatemodel/data/redrawUponColumnChange.qml new file mode 100644 index 0000000000..206133bb39 --- /dev/null +++ b/tests/auto/qml/qqmldelegatemodel/data/redrawUponColumnChange.qml @@ -0,0 +1,11 @@ +import QtQuick 2.8 + +ListView { + id: root + width: 200 + height: 200 + + delegate: Text { + text: display + } +} diff --git a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp index 2571dadc79..f10c89872f 100644 --- a/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp +++ b/tests/auto/qml/qqmldelegatemodel/tst_qqmldelegatemodel.cpp @@ -27,12 +27,14 @@ ****************************************************************************/ #include <QtTest/qtest.h> +#include <QtCore/QConcatenateTablesProxyModel> +#include <QtGui/QStandardItemModel> #include <QtQml/qqmlcomponent.h> #include <QtQmlModels/private/qqmldelegatemodel_p.h> #include <QtQuick/qquickview.h> #include <QtQuick/qquickitem.h> - -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> +#include <QtTest/QSignalSpy> class tst_QQmlDelegateModel : public QQmlDataTest { @@ -47,6 +49,7 @@ private slots: void qtbug_86017(); void filterOnGroup_removeWhenCompleted(); void contextAccessedByHandler(); + void redrawUponColumnChange(); }; class AbstractItemModel : public QAbstractItemModel @@ -101,6 +104,7 @@ private: }; tst_QQmlDelegateModel::tst_QQmlDelegateModel() + : QQmlDataTest(QT_QMLTEST_DATADIR) { qmlRegisterType<AbstractItemModel>("Test", 1, 0, "AbstractItemModel"); } @@ -175,6 +179,30 @@ void tst_QQmlDelegateModel::contextAccessedByHandler() QVERIFY(root->property("works").toBool()); } +void tst_QQmlDelegateModel::redrawUponColumnChange() +{ + QStandardItemModel m1; + m1.appendRow({ + new QStandardItem("Banana"), + new QStandardItem("Coconut"), + }); + + QQuickView view(testFileUrl("redrawUponColumnChange.qml")); + QCOMPARE(view.status(), QQuickView::Ready); + view.show(); + QQuickItem *root = view.rootObject(); + root->setProperty("model", QVariant::fromValue<QObject *>(&m1)); + + QObject *item = root->property("currentItem").value<QObject *>(); + QVERIFY(item); + QCOMPARE(item->property("text").toString(), "Banana"); + + QVERIFY(root); + m1.removeColumn(0); + + QCOMPARE(item->property("text").toString(), "Coconut"); +} + QTEST_MAIN(tst_QQmlDelegateModel) #include "tst_qqmldelegatemodel.moc" diff --git a/tests/auto/qml/qqmldirparser/CMakeLists.txt b/tests/auto/qml/qqmldirparser/CMakeLists.txt index 255cc75c6a..f8e3e36ef7 100644 --- a/tests/auto/qml/qqmldirparser/CMakeLists.txt +++ b/tests/auto/qml/qqmldirparser/CMakeLists.txt @@ -12,14 +12,12 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmldirparser SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmldirparser.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::Qml Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmldirparser/tst_qqmldirparser.cpp b/tests/auto/qml/qqmldirparser/tst_qqmldirparser.cpp index 8f0c58653b..64658e8546 100644 --- a/tests/auto/qml/qqmldirparser/tst_qqmldirparser.cpp +++ b/tests/auto/qml/qqmldirparser/tst_qqmldirparser.cpp @@ -26,8 +26,6 @@ ** ****************************************************************************/ -#include "../../shared/util.h" - #include <qtest.h> #include <QObject> #include <QQmlEngine> @@ -35,6 +33,7 @@ #include <private/qqmljsdiagnosticmessage_p.h> #include <private/qqmldirparser_p.h> #include <QDebug> +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <algorithm> @@ -52,6 +51,7 @@ private slots: }; tst_qqmldirparser::tst_qqmldirparser() + : QQmlDataTest(QT_QMLTEST_DATADIR) { } diff --git a/tests/auto/qml/qqmlecmascript/BLACKLIST b/tests/auto/qml/qqmlecmascript/BLACKLIST deleted file mode 100644 index bd25566eef..0000000000 --- a/tests/auto/qml/qqmlecmascript/BLACKLIST +++ /dev/null @@ -1,2 +0,0 @@ -[gcCrashRegressionTest] -macos arm diff --git a/tests/auto/qml/qqmlecmascript/CMakeLists.txt b/tests/auto/qml/qqmlecmascript/CMakeLists.txt index 5c5bd528ed..70f010c082 100644 --- a/tests/auto/qml/qqmlecmascript/CMakeLists.txt +++ b/tests/auto/qml/qqmlecmascript/CMakeLists.txt @@ -12,18 +12,15 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlecmascript SOURCES - ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h - ../../shared/util.cpp ../../shared/util.h testtypes.cpp testtypes.h tst_qqmlecmascript.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::Network Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlecmascript/data/Lib.js b/tests/auto/qml/qqmlecmascript/data/Lib.js new file mode 100644 index 0000000000..67d4f7f56d --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/Lib.js @@ -0,0 +1,3 @@ +.pragma library + +function f() { return 42 } diff --git a/tests/auto/qml/qqmlecmascript/data/PreNamed.qml b/tests/auto/qml/qqmlecmascript/data/PreNamed.qml new file mode 100644 index 0000000000..dc991e674f --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/PreNamed.qml @@ -0,0 +1,11 @@ +import QtQml + +QtObject { + property QtObject other: QtObject { + objectName: "original" + } + objectName: other.objectName + function updateOriginal() { + other.objectName = "updated" + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/aliasPropertyToIC.qml b/tests/auto/qml/qqmlecmascript/data/aliasPropertyToIC.qml new file mode 100644 index 0000000000..17116bb091 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/aliasPropertyToIC.qml @@ -0,0 +1,11 @@ +import QtQml + + +QtObject { + id: root + + component Test : QtObject {} + + property alias myalias: other + property var direct: Test { id: other } +} diff --git a/tests/auto/qml/qqmlecmascript/data/checkDateTime-nonstandardFormat2.qml b/tests/auto/qml/qqmlecmascript/data/checkDateTime-nonstandardFormat2.qml new file mode 100644 index 0000000000..3fd3c05024 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/checkDateTime-nonstandardFormat2.qml @@ -0,0 +1,10 @@ +import Qt.test 1.0 +import QtQml 2.15 + + +MyTypeObject { + Component.onCompleted: { + dateTimeProperty = new Date("Sun, 25 Mar 2018 11:10:49 GMT") + boolProperty = !Number.isNaN(dateTimeProperty) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/enums.1.qml b/tests/auto/qml/qqmlecmascript/data/enums.1.qml index b9295c5c89..379a6efc8e 100644 --- a/tests/auto/qml/qqmlecmascript/data/enums.1.qml +++ b/tests/auto/qml/qqmlecmascript/data/enums.1.qml @@ -35,4 +35,7 @@ MyQmlObject { // Enum values defined both in a type and a related type property int l: MyQmlObject.MultiplyDefined + + // Enum arithmetic + property int m: MyQmlObject.EnumValue2 | MyQmlObject.EnumValue3 } diff --git a/tests/auto/qml/qqmlecmascript/data/functionAsDefaultArgument.qml b/tests/auto/qml/qqmlecmascript/data/functionAsDefaultArgument.qml new file mode 100644 index 0000000000..9f576d1af8 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/functionAsDefaultArgument.qml @@ -0,0 +1,8 @@ +import QtQml 2.15 + +QtObject { + id: root + + function f(inner=function(){ root.objectName = "didRun" } ){ inner() } + Component.onCompleted: f() +} diff --git a/tests/auto/qml/qqmlecmascript/data/generatorCallsGC.qml b/tests/auto/qml/qqmlecmascript/data/generatorCallsGC.qml new file mode 100644 index 0000000000..7fe366cac8 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/generatorCallsGC.qml @@ -0,0 +1,13 @@ +import QtQml 2.15 + +QtObject { + function test_generator_gc() { + ((function*() { gc() })()).next(); + ((function*() { gc() })()).next(); + ((function*() { gc() })()).next(); + ((function*() { gc() })()).next(); + } + + Component.onCompleted: () => test_generator_gc() + +} diff --git a/tests/auto/qml/qqmlecmascript/data/icUsingJSLib.qml b/tests/auto/qml/qqmlecmascript/data/icUsingJSLib.qml new file mode 100644 index 0000000000..507027e101 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/icUsingJSLib.qml @@ -0,0 +1,12 @@ +import QtQml + +import "Lib.js" as Lib + +QtObject { + component C : QtObject { + property int num: Lib.f() + } + + property var test: C { id: c } + property alias num: c.num +} diff --git a/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js new file mode 100644 index 0000000000..f51ab662ab --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.js @@ -0,0 +1,29 @@ +function init() { + Array.prototype.doPush = Array.prototype.push +} + +function nasty() { + var sc_Vector = Array; + var push = sc_Vector.prototype.doPush; + + // Change the memberData to hold something nasty on the current internalClass + sc_Vector.prototype.doPush = 5; + + // Trigger a re-allocation of memberData + for (var i = 0; i < 256; ++i) + sc_Vector.prototype[i + "string"] = function() { return 98; } + + // Change the (new) memberData back, to hold our doPush function again. + // This should propagate a protoId change all the way up to the lookup. + sc_Vector.prototype.doPush = push; +} + +function func() { + var b = []; + + // This becomes a lookup internally, which stores protoId and a pointer + // into the memberData. It should get invalidated when memberData is re-allocated. + b.doPush(3); + + return b; +} diff --git a/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml new file mode 100644 index 0000000000..e313770bf5 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/internalClassParentGc.qml @@ -0,0 +1,13 @@ +import QtQml + +import "internalClassParentGc.js" as Foo + +QtObject { + Component.onCompleted: { + gc(); + Foo.init(); + Foo.func(); + Foo.nasty(); + objectName = Foo.func()[0]; + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/methodTypeMismatch.qml b/tests/auto/qml/qqmlecmascript/data/methodTypeMismatch.qml new file mode 100644 index 0000000000..fdf5f4ea11 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/methodTypeMismatch.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Item { + id: self + property font myFont + property int notMyFont + + property var object + + function callWithFont() { + object.method_gadget(myFont) // should be fine + } + function callWithInt() { + object.method_gadget(123) + } + function callWithInt2() { + object.method_gadget(notMyFont) + } + function callWithNull() { + object.method_gadget(null) + } + function callWithAllowedNull() { + object.method_qobject(null) + } +} diff --git a/tests/auto/qml/qqmlecmascript/data/qpropertyBindingReplacement.qml b/tests/auto/qml/qqmlecmascript/data/qpropertyBindingReplacement.qml new file mode 100644 index 0000000000..478a88678b --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/qpropertyBindingReplacement.qml @@ -0,0 +1,6 @@ +import QtQml + +PreNamed { + objectName: "overwritten" + Component.onCompleted: updateOriginal() +} diff --git a/tests/auto/qml/qqmlecmascript/data/readOnlyBindable.qml b/tests/auto/qml/qqmlecmascript/data/readOnlyBindable.qml new file mode 100644 index 0000000000..116036c9ff --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/readOnlyBindable.qml @@ -0,0 +1,7 @@ +import Qt.test +import QtQuick + +ReadOnlyBindable { + property int v: 12 + x: v +} diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp index 87d8ed0c1f..cd83702d3a 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.cpp +++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp @@ -560,6 +560,7 @@ void registerTypes() qmlRegisterType<Receiver>("Qt.test", 1,0, "Receiver"); qmlRegisterType<Sender>("Qt.test", 1,0, "Sender"); + qmlRegisterTypesAndRevisions<ReadOnlyBindable>("Qt.test", 1); } #include "testtypes.moc" diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index acc066fddd..a3df73972e 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -833,12 +833,38 @@ public: Q_INVOKABLE void method_unknown(NonRegisteredType) { invoke(28); } + Q_PROPERTY(QFont someFont READ someFont WRITE setSomeFont NOTIFY someFontChanged); + QFont someFont() { return m_someFont; } + void setSomeFont(const QFont &f) + { + if (f == m_someFont) + return; + m_someFont = f; + emit someFontChanged(); + } + Q_INVOKABLE void method_gadget(QFont f) + { + invoke(40); + m_actuals << f; + } + Q_INVOKABLE void method_qobject(QObject *o) + { + invoke(41); + m_actuals << QVariant::fromValue(o); + } + private: friend class MyInvokableBaseObject; void invoke(int idx) { if (m_invoked != -1) m_invokedError = true; m_invoked = idx;} int m_invoked; bool m_invokedError; QVariantList m_actuals; + + QFont m_someFont; + +public: +Q_SIGNALS: + void someFontChanged(); }; MyInvokableBaseObject::~MyInvokableBaseObject() {} @@ -1847,6 +1873,25 @@ public slots: int slot1(int i, int j, int k) {return i+j+k;} }; +class ReadOnlyBindable : public QObject +{ + Q_OBJECT + QML_ELEMENT + Q_PROPERTY(int x READ x WRITE setX BINDABLE bindableX) + Q_OBJECT_BINDABLE_PROPERTY(ReadOnlyBindable, int, _xProp) + +public: + ReadOnlyBindable(QObject *parent = nullptr) + : QObject(parent) + { + setX(7); + } + + int x() const { return _xProp.value(); } + void setX(int x) { _xProp.setValue(x); } + QBindable<int> bindableX() const { return &_xProp; } +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index d8d90b1aff..f47c7132a2 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -39,8 +39,6 @@ #include <private/qqmlvmemetaobject_p.h> #include <private/qv4qmlcontext_p.h> #include "testtypes.h" -#include "testhttpserver.h" -#include "../../shared/util.h" #include <private/qv4functionobject_p.h> #include <private/qv4scopedvalue_p.h> #include <private/qv4jscall_p.h> @@ -54,6 +52,8 @@ #include <private/qqmlabstractbinding_p.h> #include <private/qqmlvaluetypeproxybinding_p.h> #include <QtCore/private/qproperty_p.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> +#include <QtQuickTestUtils/private/testhttpserver_p.h> #ifdef Q_CC_MSVC #define NO_INLINE __declspec(noinline) @@ -72,6 +72,9 @@ class tst_qqmlecmascript : public QQmlDataTest { Q_OBJECT +public: + tst_qqmlecmascript(); + private slots: void initTestCase() override; void arrayIncludesValueType(); @@ -112,6 +115,7 @@ private slots: void outerBindingOverridesInnerBinding(); void aliasPropertyAndBinding(); void aliasPropertyReset(); + void aliasPropertyToIC(); void nonExistentAttachedObject(); void scope(); void importScope(); @@ -244,6 +248,8 @@ private slots: void function(); void topLevelGeneratorFunction(); void generatorCrashNewProperty(); + void generatorCallsGC(); + void noYieldInInnerFunction(); void qtbug_10696(); void qtbug_11606(); void qtbug_11600(); @@ -305,6 +311,7 @@ private slots: void replaceBinding(); void bindingBoundFunctions(); void qpropertyAndQtBinding(); + void qpropertyBindingReplacement(); void deleteRootObjectInCreation(); void onDestruction(); void onDestructionViaGC(); @@ -410,11 +417,21 @@ private slots: void frozenQObject(); void constPointer(); + void icUsingJSLib(); + void optionalChainEval(); void optionalChainDelete(); void optionalChainNull(); void asCast(); + void functionNameInFunctionScope(); + void functionAsDefaultArgument(); + + void internalClassParentGc(); + void methodTypeMismatch(); + + void doNotCrashOnReadOnlyBindable(); + private: // static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter); static void verifyContextLifetime(const QQmlRefPointer<QQmlContextData> &ctxt); @@ -439,6 +456,11 @@ static void gc(QQmlEngine &engine) } +tst_qqmlecmascript::tst_qqmlecmascript() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_qqmlecmascript::initTestCase() { QQmlDataTest::initTestCase(); @@ -710,6 +732,9 @@ void tst_qqmlecmascript::checkDateTime_data() QTest::newRow("nonstandard-format") << testFileUrl("checkDateTime-nonstandardFormat.qml") << QDateTime::fromString("1991-08-25 20:57:08 GMT+0000", "yyyy-MM-dd hh:mm:ss t"); + QTest::newRow("nonstandard-format2") + << testFileUrl("checkDateTime-nonstandardFormat2.qml") + << QDateTime::fromString("Sun, 25 Mar 2018 11:10:49 GMT", "ddd, d MMM yyyy hh:mm:ss t"); } void tst_qqmlecmascript::checkDateTime() @@ -1375,6 +1400,7 @@ void tst_qqmlecmascript::enums() QCOMPARE(object->property("j").toInt(), 19); QCOMPARE(object->property("k").toInt(), 42); QCOMPARE(object->property("l").toInt(), 333); + QCOMPARE(object->property("m").toInt(), 3); } // Non-existent enums { @@ -1815,6 +1841,24 @@ void tst_qqmlecmascript::aliasPropertyReset() QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false)); } +void tst_qqmlecmascript::aliasPropertyToIC() +{ + QQmlEngine engine; + std::unique_ptr<QObject> root; + + // test that a manual write (of undefined) to a resettable aliased property succeeds + QQmlComponent c(&engine, testFileUrl("aliasPropertyToIC.qml")); + root.reset(c.create()); + QVERIFY(root); + auto mo = root->metaObject(); + int aliasIndex = mo->indexOfProperty("myalias"); + auto prop = mo->property(aliasIndex); + QVERIFY(prop.isAlias()); + auto fromAlias = prop.read(root.get()).value<QObject *>(); + auto direct = root->property("direct").value<QObject *>(); + QCOMPARE(fromAlias, direct); +} + void tst_qqmlecmascript::componentCreation_data() { QTest::addColumn<QString>("method"); @@ -3290,6 +3334,19 @@ void tst_qqmlecmascript::callQtInvokables() QJSValue callback = qvariant_cast<QJSValue>(o->actuals().at(1)); QVERIFY(!callback.isNull()); QVERIFY(callback.isCallable()); + + o->reset(); + QVERIFY(EVALUATE_VALUE("object.method_gadget(object.someFont)", + QV4::Primitive::undefinedValue())); + QCOMPARE(o->error(), false); + QCOMPARE(o->invoked(), 40); + QCOMPARE(o->actuals(), QVariantList() << QVariant(o->someFont())); + + o->reset(); + QVERIFY(EVALUATE_ERROR("object.method_gadget(123)")); + QCOMPARE(o->error(), false); + QCOMPARE(o->invoked(), -1); + QCOMPARE(o->actuals(), QVariantList()); } void tst_qqmlecmascript::resolveClashingProperties() @@ -6397,6 +6454,28 @@ void tst_qqmlecmascript::generatorCrashNewProperty() QCOMPARE(o->property("c").toInt(), 42); } +void tst_qqmlecmascript::generatorCallsGC() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("generatorCallsGC.qml")); + + QScopedPointer<QObject> o(component.create()); // should not crash + QVERIFY2(o != nullptr, qPrintable(component.errorString())); +} + +void tst_qqmlecmascript::noYieldInInnerFunction() +{ + QJSEngine engine; + const QString program = R"( + function *a() { + (function() { yield 1; })(); + }; + )"; + auto result = engine.evaluate(program); + QVERIFY(result.isError()); + QCOMPARE(result.errorType(), QJSValue::SyntaxError); +} + // Test the "Qt.include" method void tst_qqmlecmascript::include() { @@ -7552,6 +7631,15 @@ void tst_qqmlecmascript::qpropertyAndQtBinding() QCOMPARE(root->complex.value(), 150); } +void tst_qqmlecmascript::qpropertyBindingReplacement() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("qpropertyBindingReplacement.qml")); + QScopedPointer<QObject> root(c.create()); + QVERIFY(root); + QCOMPARE(root->objectName(), u"overwritten"_qs); +} + void tst_qqmlecmascript::deleteRootObjectInCreation() { QQmlEngine engine; @@ -9694,6 +9782,15 @@ void tst_qqmlecmascript::constPointer() QVERIFY(root->property("propertyOk").toBool()); } +void tst_qqmlecmascript::icUsingJSLib() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("icUsingJSLib.qml")); + QScopedPointer<QObject> root(component.create()); + QVERIFY2(root, qPrintable(component.errorString())); + QCOMPARE(root->property("num").toInt(), 42); +} + void tst_qqmlecmascript::optionalChainEval() { QQmlEngine qmlengine; @@ -9804,6 +9901,178 @@ void tst_qqmlecmascript::asCast() QCOMPARE(qvariant_cast<QObject *>(root->property("rectangleAsRectangle")), rectangle); } +void tst_qqmlecmascript::functionNameInFunctionScope() +{ + QJSEngine engine; + QJSValue result = engine.evaluate(R"( + var a = {}; + var foo = function foo() { + return foo; + } + a.foo = foo(); + + function bar() { + bar = 2; + } + bar() + a.bar = bar; + + var baz = function baz() { + baz = 3; + } + baz() + a.baz = baz; + + var foo2 = function() { + return foo2; + } + a.foo2 = foo2(); + + var baz2 = function() { + baz2 = 3; + } + baz2() + a.baz2 = baz2; + a + + )"); + + QVERIFY(!result.isError()); + const QJSManagedValue m(result, &engine); + + QVERIFY(m.property("foo").isCallable()); + QCOMPARE(m.property("bar").toInt(), 2); + QVERIFY(m.property("baz").isCallable()); + QVERIFY(m.property("foo2").isCallable()); + QCOMPARE(m.property("baz2").toInt(), 3); + + const QJSValue getterInClass = engine.evaluate(R"( + class Tester { + constructor () { + this.a = 1; + this.b = 1; + } + + get sum() { + const sum = this.a + this.b; + return sum; + } + } + )"); + + QVERIFY(!getterInClass.isError()); + + const QJSValue innerName = engine.evaluate(R"( + const a = 2; + var b = function a() { return a }; + ({a: a, b: b, c: b()}) + )"); + + QVERIFY(!innerName.isError()); + const QJSManagedValue m2(innerName, &engine); + QCOMPARE(m2.property("a").toInt(), 2); + QVERIFY(m2.property("b").isCallable()); + QVERIFY(m2.property("c").isCallable()); +} + + +void tst_qqmlecmascript::functionAsDefaultArgument() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("functionAsDefaultArgument.qml")); + QScopedPointer root(component.create()); + QVERIFY(root); + QCOMPARE(root->objectName(), "didRun"); +} + +void tst_qqmlecmascript::internalClassParentGc() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("internalClassParentGc.qml")); + QScopedPointer root(component.create()); + QVERIFY(root); + QCOMPARE(root->objectName(), "3"); +} + +void tst_qqmlecmascript::methodTypeMismatch() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("methodTypeMismatch.qml")); + + QScopedPointer<MyInvokableObject> object(new MyInvokableObject()); + + QScopedPointer<QObject> o(component.create()); + QVERIFY2(o, qPrintable(component.errorString())); + o->setProperty("object", QVariant::fromValue(object.get())); + + auto mo = o->metaObject(); + QVERIFY(mo); + + auto method = mo->method(mo->indexOfMethod("callWithFont()")); + QVERIFY(method.isValid()); + QVERIFY(method.invoke(o.get())); + QCOMPARE(object->actuals(), QVariantList() << QVariant(object->someFont())); + + QRegularExpression argumentConversionErrorMatcher("Could not convert argument 0"); + QRegularExpression argumentConversionErrorMatcher2(".*/methodTypeMismatch.qml"); + QRegularExpression typeErrorMatcher( + ".*/methodTypeMismatch\\.qml:..: TypeError: Passing incompatible arguments to C\\+\\+ " + "functions from JavaScript is not allowed."); + + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher); + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher2); + QTest::ignoreMessage(QtWarningMsg, typeErrorMatcher); + object->reset(); + method = mo->method(mo->indexOfMethod("callWithInt()")); + QVERIFY(method.isValid()); + QVERIFY(method.invoke(o.get())); + QCOMPARE(object->actuals().size(), + 0); // actuals() should not contain reinterpret_cast<QFont>(123) !!! + + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher); + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher2); + QTest::ignoreMessage(QtWarningMsg, typeErrorMatcher); + object->reset(); + method = mo->method(mo->indexOfMethod("callWithInt2()")); + QVERIFY(method.isValid()); + QVERIFY(method.invoke(o.get())); + QCOMPARE(object->actuals().size(), + 0); // actuals() should not contain reinterpret_cast<QFont>(0) !!! + + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher); + QTest::ignoreMessage(QtWarningMsg, argumentConversionErrorMatcher2); + QTest::ignoreMessage(QtWarningMsg, typeErrorMatcher); + object->reset(); + method = mo->method(mo->indexOfMethod("callWithNull()")); + QVERIFY(method.isValid()); + QVERIFY(method.invoke(o.get())); + QCOMPARE(object->actuals().size(), + 0); // actuals() should not contain reinterpret_cast<QFont>(nullptr) !!! + + // make sure that null is still accepted by functions accepting, e.g., a QObject*! + object->reset(); + method = mo->method(mo->indexOfMethod("callWithAllowedNull()")); + QVERIFY(method.isValid()); + QVERIFY(method.invoke(o.get())); + QCOMPARE(object->actuals(), QVariantList() << QVariant::fromValue((QObject *)nullptr)); +} + +void tst_qqmlecmascript::doNotCrashOnReadOnlyBindable() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("readOnlyBindable.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); +#ifndef QT_NO_DEBUG + QTest::ignoreMessage( + QtWarningMsg, + "setBinding: Could not set binding via bindable interface. " + "The QBindable is read-only."); +#endif + QScopedPointer<QObject> o(c.create()); + QVERIFY(o); + QCOMPARE(o->property("x").toInt(), 7); +} + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlengine/CMakeLists.txt b/tests/auto/qml/qqmlengine/CMakeLists.txt index f143dddb25..43fec7cb90 100644 --- a/tests/auto/qml/qqmlengine/CMakeLists.txt +++ b/tests/auto/qml/qqmlengine/CMakeLists.txt @@ -12,16 +12,14 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlengine SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlengine.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::Network Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) @@ -38,6 +36,9 @@ qt_internal_add_resource(tst_qqmlengine "qmake_immediate" ${qmake_immediate_resource_files} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmlengine) +endif() ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index e1dff63e03..d2ec48ffb4 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -26,7 +26,6 @@ ** ****************************************************************************/ -#include "../../shared/util.h" #include <QQmlEngine> #include <QQmlContext> #include <QNetworkAccessManager> @@ -46,12 +45,13 @@ #include <private/qqmltypedata_p.h> #include <private/qqmlcomponentattached_p.h> #include <QQmlAbstractUrlInterceptor> +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlengine : public QQmlDataTest { Q_OBJECT public: - tst_qqmlengine() {} + tst_qqmlengine() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; @@ -91,6 +91,7 @@ private slots: void listWrapperAsListReference(); void attachedObjectAsObject(); void listPropertyAsQJSValue(); + void stringToColor(); public slots: QObject *createAQObjectForOwnershipTest () @@ -1410,6 +1411,31 @@ void tst_qqmlengine::listPropertyAsQJSValue() QCOMPARE(prop.at(&prop, 0), &c); } +void tst_qqmlengine::stringToColor() +{ + QQmlEngine engine; + + // Make it import QtQuick, so that color becomes available. + QQmlComponent c(&engine); + c.setData("import QtQuick\nItem {}", QUrl()); + QVERIFY(c.isReady()); + QScopedPointer<QObject> o(c.create()); + + const QMetaType metaType(QMetaType::QColor); + QVariant color(metaType); + QVERIFY(engine.handle()->metaTypeFromJS( + engine.handle()->newString(QStringLiteral("#abcdef"))->asReturnedValue(), + metaType, color.data())); + QVERIFY(color.isValid()); + QCOMPARE(color.metaType(), metaType); + + QVariant variant(QStringLiteral("#abcdef")); + QVERIFY(variant.convert(metaType)); + QCOMPARE(variant.metaType(), metaType); + + QCOMPARE(color, variant); +} + QTEST_MAIN(tst_qqmlengine) #include "tst_qqmlengine.moc" diff --git a/tests/auto/qml/qqmlenginecleanup/BLACKLIST b/tests/auto/qml/qqmlenginecleanup/BLACKLIST index 4fb1d9be4c..f88fad8dd8 100644 --- a/tests/auto/qml/qqmlenginecleanup/BLACKLIST +++ b/tests/auto/qml/qqmlenginecleanup/BLACKLIST @@ -1,2 +1,5 @@ [test_customModuleCleanup] windows gcc ci +# QTBUG-102833 +[test_customModuleCleanup] +android diff --git a/tests/auto/qml/qqmlenginecleanup/CMakeLists.txt b/tests/auto/qml/qqmlenginecleanup/CMakeLists.txt index f8637755b7..fcc9358cd3 100644 --- a/tests/auto/qml/qqmlenginecleanup/CMakeLists.txt +++ b/tests/auto/qml/qqmlenginecleanup/CMakeLists.txt @@ -4,15 +4,20 @@ ## tst_qqmlenginecleanup Test: ##################################################################### +# Collect test data +file(GLOB_RECURSE test_data_glob + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + data/*) +list(APPEND test_data ${test_data_glob}) + qt_internal_add_test(tst_qqmlenginecleanup SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlenginecleanup.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Qml Qt::QmlPrivate + Qt::QuickTestUtilsPrivate + TESTDATA ${test_data} ) ## Scopes: diff --git a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp index 31a71d5e6a..d8bf86d91a 100644 --- a/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp +++ b/tests/auto/qml/qqmlenginecleanup/tst_qqmlenginecleanup.cpp @@ -26,20 +26,20 @@ ** ****************************************************************************/ -#include "../../shared/util.h" #include <QtCore/QObject> #include <QtQml/qqml.h> #include <QtQml/QQmlEngine> #include <QtQml/QQmlComponent> #include <private/qhashedstring_p.h> #include <private/qqmlmetatype_p.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> //Separate test, because if engine cleanup attempts fail they can easily break unrelated tests class tst_qqmlenginecleanup : public QQmlDataTest { Q_OBJECT public: - tst_qqmlenginecleanup() {} + tst_qqmlenginecleanup() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void test_qmlClearTypeRegistrations(); diff --git a/tests/auto/qml/qqmlerror/CMakeLists.txt b/tests/auto/qml/qqmlerror/CMakeLists.txt index 7bb8715b01..359dd82658 100644 --- a/tests/auto/qml/qqmlerror/CMakeLists.txt +++ b/tests/auto/qml/qqmlerror/CMakeLists.txt @@ -12,15 +12,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlerror SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlerror.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlerror/tst_qqmlerror.cpp b/tests/auto/qml/qqmlerror/tst_qqmlerror.cpp index f282e60417..6ddf7dfe48 100644 --- a/tests/auto/qml/qqmlerror/tst_qqmlerror.cpp +++ b/tests/auto/qml/qqmlerror/tst_qqmlerror.cpp @@ -29,11 +29,15 @@ #include <qtest.h> #include <QQmlError> #include <QDebug> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlerror : public QQmlDataTest { Q_OBJECT + +public: + tst_qqmlerror(); + private slots: void url(); void description(); @@ -45,6 +49,11 @@ private slots: void debug(); }; +tst_qqmlerror::tst_qqmlerror() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_qqmlerror::url() { QQmlError error; diff --git a/tests/auto/qml/qqmlexpression/CMakeLists.txt b/tests/auto/qml/qqmlexpression/CMakeLists.txt index cc5e69d4bc..ec90797d41 100644 --- a/tests/auto/qml/qqmlexpression/CMakeLists.txt +++ b/tests/auto/qml/qqmlexpression/CMakeLists.txt @@ -12,15 +12,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlexpression SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlexpression.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp index 494d5af2b8..aec1816b82 100644 --- a/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp +++ b/tests/auto/qml/qqmlexpression/tst_qqmlexpression.cpp @@ -32,13 +32,13 @@ #include <QtQml/qqmlcomponent.h> #include <QtQml/qqmlexpression.h> #include <QtQml/qqmlscriptstring.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlexpression : public QQmlDataTest { Q_OBJECT public: - tst_qqmlexpression() {} + tst_qqmlexpression() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void scriptString(); diff --git a/tests/auto/qml/qqmlfile/tst_qqmlfile.cpp b/tests/auto/qml/qqmlfile/tst_qqmlfile.cpp index a1c8daddcf..77909d8576 100644 --- a/tests/auto/qml/qqmlfile/tst_qqmlfile.cpp +++ b/tests/auto/qml/qqmlfile/tst_qqmlfile.cpp @@ -38,19 +38,145 @@ public: tst_qqmlfile() {} private Q_SLOTS: + void isLocalFile_data(); + void isLocalFile(); + + void urlToLocalFileOrQrcOverloads_data(); void urlToLocalFileOrQrcOverloads(); + +private: + void urlData(); }; +void tst_qqmlfile::urlData() +{ + QTest::addColumn<QString>("urlString"); + QTest::addColumn<bool>("isLocal"); + QTest::addColumn<QString>("localPath"); + + const QString invalid; + const QString relative = QStringLiteral("foo/bar"); + const QString absolute = QStringLiteral("/foo/bar"); + + QTest::addRow("plain empty") << QStringLiteral("") << false << invalid; + QTest::addRow("plain no slash") << QStringLiteral("foo/bar") << false << invalid; + QTest::addRow("plain 1 slash") << QStringLiteral("/foo/bar") << false << invalid; + QTest::addRow("plain 2 slashes") << QStringLiteral("//foo/bar") << false << invalid; + QTest::addRow("plain 3 slashes") << QStringLiteral("///foo/bar") << false << invalid; + + QTest::addRow(": empty") << QStringLiteral(":") << false << invalid; + QTest::addRow(": no slash") << QStringLiteral(":foo/bar") << false << invalid; + QTest::addRow(": 1 slash") << QStringLiteral(":/foo/bar") << false << invalid; + QTest::addRow(": 2 slashes") << QStringLiteral("://foo/bar") << false << invalid; + QTest::addRow(": 3 slashes") << QStringLiteral(":///foo/bar") << false << invalid; + + QTest::addRow("C empty") << QStringLiteral("C:") << false << invalid; + QTest::addRow("C no slash") << QStringLiteral("C:foo/bar") << false << invalid; + QTest::addRow("C 1 slash") << QStringLiteral("C:/foo/bar") << false << invalid; + QTest::addRow("C 2 slashes") << QStringLiteral("C://foo/bar") << false << invalid; + QTest::addRow("C 3 slashes") << QStringLiteral("C:///foo/bar") << false << invalid; + + QTest::addRow("file empty") << QStringLiteral("file:") << true << QString(); + QTest::addRow("file no slash") << QStringLiteral("file:foo/bar") << true << relative; + QTest::addRow("file 1 slash") << QStringLiteral("file:/foo/bar") << true << absolute; + QTest::addRow("file 2 slashes") << QStringLiteral("file://foo/bar") << true << QStringLiteral("//foo/bar"); + QTest::addRow("file 3 slashes") << QStringLiteral("file:///foo/bar") << true << absolute; + + QTest::addRow("qrc empty") << QStringLiteral("qrc:") << true << QStringLiteral(":"); + QTest::addRow("qrc no slash") << QStringLiteral("qrc:foo/bar") << true << u':' + relative; + QTest::addRow("qrc 1 slash") << QStringLiteral("qrc:/foo/bar") << true << u':' + absolute; + QTest::addRow("qrc 2 slashes") << QStringLiteral("qrc://foo/bar") << false << invalid; + QTest::addRow("qrc 3 slashes") << QStringLiteral("qrc:///foo/bar") << true << u':' + absolute; + + QTest::addRow("file+stuff empty") << QStringLiteral("file+stuff:") << false << invalid; + QTest::addRow("file+stuff no slash") << QStringLiteral("file+stuff:foo/bar") << false << invalid; + QTest::addRow("file+stuff 1 slash") << QStringLiteral("file+stuff:/foo/bar") << false << invalid; + QTest::addRow("file+stuff 2 slashes") << QStringLiteral("file+stuff://foo/bar") << false << invalid; + QTest::addRow("file+stuff 3 slashes") << QStringLiteral("file+stuff:///foo/bar") << false << invalid; + + // "assets:" and "content:" URLs are only treated as local files on android. In contrast to + // "qrc:" and "file:" we're not trying to be clever about multiple slashes. Two slashes are + // prohibited as that says part of what we would recognize as path is actually a URL authority. + // Everything else is android's problem. + +#ifdef Q_OS_ANDROID + const bool hasAssetsAndContent = true; +#else + const bool hasAssetsAndContent = false; +#endif + + const QString assetsEmpty = hasAssetsAndContent ? QStringLiteral("assets:") : invalid; + const QString assetsRelative = hasAssetsAndContent ? (QStringLiteral("assets:") + relative) : invalid; + const QString assetsAbsolute = hasAssetsAndContent ? (QStringLiteral("assets:") + absolute) : invalid; + const QString assetsThreeSlashes = hasAssetsAndContent ? (QStringLiteral("assets://") + absolute) : invalid; + + QTest::addRow("assets empty") << QStringLiteral("assets:") << hasAssetsAndContent << assetsEmpty; + QTest::addRow("assets no slash") << QStringLiteral("assets:foo/bar") << hasAssetsAndContent << assetsRelative; + QTest::addRow("assets 1 slash") << QStringLiteral("assets:/foo/bar") << hasAssetsAndContent << assetsAbsolute; + QTest::addRow("assets 2 slashes") << QStringLiteral("assets://foo/bar") << false << invalid; + QTest::addRow("assets 3 slashes") << QStringLiteral("assets:///foo/bar") << hasAssetsAndContent << assetsThreeSlashes; + + const QString contentEmpty = hasAssetsAndContent ? QStringLiteral("content:") : invalid; + const QString contentRelative = hasAssetsAndContent ? (QStringLiteral("content:") + relative) : invalid; + const QString contentAbsolute = hasAssetsAndContent ? (QStringLiteral("content:") + absolute) : invalid; + const QString contentThreeSlashes = hasAssetsAndContent ? (QStringLiteral("content://") + absolute) : invalid; + + QTest::addRow("content empty") << QStringLiteral("content:") << hasAssetsAndContent << contentEmpty; + QTest::addRow("content no slash") << QStringLiteral("content:foo/bar") << hasAssetsAndContent << contentRelative; + QTest::addRow("content 1 slash") << QStringLiteral("content:/foo/bar") << hasAssetsAndContent << contentAbsolute; + QTest::addRow("content 2 slashes") << QStringLiteral("content://foo/bar") << false << invalid; + QTest::addRow("content 3 slashes") << QStringLiteral("content:///foo/bar") << hasAssetsAndContent << contentThreeSlashes; + + + // These are local files everywhere. Their paths are only meaningful on android, though. + // The inner slashes of the path do not influence the URL parsing. + + QTest::addRow("file:assets empty") << QStringLiteral("file:assets:") << true << QStringLiteral("assets:"); + QTest::addRow("file:assets no slash") << QStringLiteral("file:assets:foo/bar") << true << QStringLiteral("assets:foo/bar"); + QTest::addRow("file:assets 1 slash") << QStringLiteral("file:assets:/foo/bar") << true << QStringLiteral("assets:/foo/bar"); + QTest::addRow("file:assets 2 slashes") << QStringLiteral("file:assets://foo/bar") << true << QStringLiteral("assets://foo/bar"); + QTest::addRow("file:assets 3 slashes") << QStringLiteral("file:assets:///foo/bar") << true << QStringLiteral("assets:///foo/bar"); + + QTest::addRow("file:content empty") << QStringLiteral("file:content:") << true << QStringLiteral("content:"); + QTest::addRow("file:content no slash") << QStringLiteral("file:content:foo/bar") << true << QStringLiteral("content:foo/bar"); + QTest::addRow("file:content 1 slash") << QStringLiteral("file:content:/foo/bar") << true << QStringLiteral("content:/foo/bar"); + QTest::addRow("file:content 2 slashes") << QStringLiteral("file:content://foo/bar") << true << QStringLiteral("content://foo/bar"); + QTest::addRow("file:content 3 slashes") << QStringLiteral("file:content:///foo/bar") << true << QStringLiteral("content:///foo/bar"); +} + +void tst_qqmlfile::isLocalFile_data() +{ + urlData(); +} + +void tst_qqmlfile::isLocalFile() +{ + QFETCH(QString, urlString); + QFETCH(bool, isLocal); + + const QUrl url(urlString); + + QCOMPARE(QQmlFile::isLocalFile(urlString), isLocal); + QCOMPARE(QQmlFile::isLocalFile(url), isLocal); +} + +void tst_qqmlfile::urlToLocalFileOrQrcOverloads_data() +{ + urlData(); +} + void tst_qqmlfile::urlToLocalFileOrQrcOverloads() { - const QString urlString = QStringLiteral("qrc:///example.qml"); + QFETCH(QString, urlString); + QFETCH(QString, localPath); + const QUrl url(urlString); const QString pathForUrlString = QQmlFile::urlToLocalFileOrQrc(urlString); const QString pathForUrl = QQmlFile::urlToLocalFileOrQrc(url); - QCOMPARE(pathForUrlString, pathForUrl); - QCOMPARE(pathForUrlString, QStringLiteral(":/example.qml")); + QCOMPARE(pathForUrlString, localPath); + QCOMPARE(pathForUrl, localPath); } QTEST_GUILESS_MAIN(tst_qqmlfile) diff --git a/tests/auto/qml/qqmlfileselector/CMakeLists.txt b/tests/auto/qml/qqmlfileselector/CMakeLists.txt index 61707f79c7..4d7c4f840b 100644 --- a/tests/auto/qml/qqmlfileselector/CMakeLists.txt +++ b/tests/auto/qml/qqmlfileselector/CMakeLists.txt @@ -12,18 +12,20 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlfileselector SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlfileselector.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmlfileselector) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qqmlfileselector/data/qmldirtest/main.qml b/tests/auto/qml/qqmlfileselector/data/qmldirtest/main.qml new file mode 100644 index 0000000000..d6dd2c9b90 --- /dev/null +++ b/tests/auto/qml/qqmlfileselector/data/qmldirtest/main.qml @@ -0,0 +1,13 @@ +import QtQuick +import qmldirtest + +Window { + width: 640 + height: 480 + visible: true + property color color: mybutton.color + + MyButton { + id: mybutton + } +} diff --git a/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+linux/MyButton.qml b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+linux/MyButton.qml new file mode 100644 index 0000000000..cc6eb967da --- /dev/null +++ b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+linux/MyButton.qml @@ -0,0 +1,7 @@ +import QtQuick + +Rectangle { + width: 300 + height: 50 + color: "blue" +} diff --git a/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+macos/MyButton.qml b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+macos/MyButton.qml new file mode 100644 index 0000000000..5bf632c48d --- /dev/null +++ b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/+macos/MyButton.qml @@ -0,0 +1,7 @@ +import QtQuick + +Rectangle { + width: 300 + height: 50 + color: "yellow" +} diff --git a/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/MyButton.qml b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/MyButton.qml new file mode 100644 index 0000000000..32db428c4f --- /dev/null +++ b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qml/MyButton.qml @@ -0,0 +1,7 @@ +import QtQuick + +Rectangle { + width: 300 + height: 50 + color: "green" +} diff --git a/tests/auto/qml/qqmlfileselector/data/qmldirtest/qmldir b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qmldir new file mode 100644 index 0000000000..ac68d9097d --- /dev/null +++ b/tests/auto/qml/qqmlfileselector/data/qmldirtest/qmldir @@ -0,0 +1,5 @@ +module qmldirtest +MyButton 1.0 qml/MyButton.qml +MyButton 1.0 qml/+linux/MyButton.qml +MyButton 1.0 qml/+macos/MyButton.qml + diff --git a/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp b/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp index bc5cd2cdae..fe55d8b056 100644 --- a/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp +++ b/tests/auto/qml/qqmlfileselector/tst_qqmlfileselector.cpp @@ -35,19 +35,19 @@ #include <QQmlContext> #include <QLoggingCategory> #include <qqmlinfo.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlfileselector : public QQmlDataTest { Q_OBJECT public: - tst_qqmlfileselector() {} + tst_qqmlfileselector() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void basicTest(); void basicTestCached(); void applicationEngineTest(); - + void qmldirCompatibility(); }; void tst_qqmlfileselector::basicTest() @@ -86,19 +86,30 @@ void tst_qqmlfileselector::basicTestCached() void tst_qqmlfileselector::applicationEngineTest() { QQmlApplicationEngine engine; -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED - QQmlFileSelector* selector = QQmlFileSelector::get(&engine); -QT_WARNING_POP - QVERIFY(selector != nullptr); - selector->setExtraSelectors(QStringList() << "basic"); + engine.setExtraFileSelectors(QStringList() << "basic"); + engine.load(testFileUrl("basicTest.qml")); - QQmlComponent component(&engine, testFileUrl("basicTest.qml")); - QObject *object = component.create(); + QVERIFY(!engine.rootObjects().isEmpty()); + QObject *object = engine.rootObjects().at(0); QVERIFY(object != nullptr); QCOMPARE(object->property("value").toString(), QString("selected")); +} - delete object; +void tst_qqmlfileselector::qmldirCompatibility() +{ + QQmlApplicationEngine engine; + engine.addImportPath(dataDirectory()); + engine.load(testFileUrl("qmldirtest/main.qml")); + QVERIFY(!engine.rootObjects().isEmpty()); + QObject *object = engine.rootObjects().at(0); + auto color = object->property("color").value<QColor>(); +#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID) + QCOMPARE(color, QColorConstants::Svg::blue); +#elif defined(Q_OS_DARWIN) + QCOMPARE(color, QColorConstants::Svg::yellow); +#else + QCOMPARE(color, QColorConstants::Svg::green); +#endif } QTEST_MAIN(tst_qqmlfileselector) diff --git a/tests/auto/qml/qqmlimport/CMakeLists.txt b/tests/auto/qml/qqmlimport/CMakeLists.txt index 3d4f01da2c..6392a527a4 100644 --- a/tests/auto/qml/qqmlimport/CMakeLists.txt +++ b/tests/auto/qml/qqmlimport/CMakeLists.txt @@ -24,15 +24,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlimport SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlimport.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::Qml Qt::QmlPrivate Qt::Quick + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlimport/data/absoluteImport.qml b/tests/auto/qml/qqmlimport/data/absoluteImport.qml new file mode 100644 index 0000000000..d182fe5b71 --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/absoluteImport.qml @@ -0,0 +1,4 @@ +import "/foo/bar/baz" + +QtObject {} + diff --git a/tests/auto/qml/qqmlimport/data/absoluteResourceImport.qml b/tests/auto/qml/qqmlimport/data/absoluteResourceImport.qml new file mode 100644 index 0000000000..74b98664aa --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/absoluteResourceImport.qml @@ -0,0 +1,4 @@ +import ":/absolute/resource/path" + +QtObject {} + diff --git a/tests/auto/qml/qqmlimport/data/importQtQuickTooling.qml b/tests/auto/qml/qqmlimport/data/importQtQuickTooling.qml new file mode 100644 index 0000000000..5b094adfff --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/importQtQuickTooling.qml @@ -0,0 +1,4 @@ +import QtQuick.tooling + +Property { +} diff --git a/tests/auto/qml/qqmlimport/data/relativeResourceImport.qml b/tests/auto/qml/qqmlimport/data/relativeResourceImport.qml new file mode 100644 index 0000000000..6a7e2b7ea5 --- /dev/null +++ b/tests/auto/qml/qqmlimport/data/relativeResourceImport.qml @@ -0,0 +1,4 @@ +import ":relative/resource/path" + +QtObject {} + diff --git a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp index 572c8771a0..7b6c33bcc9 100644 --- a/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp +++ b/tests/auto/qml/qqmlimport/tst_qqmlimport.cpp @@ -34,12 +34,15 @@ #include <QtQuick/qquickitem.h> #include <private/qqmlimport_p.h> #include <private/qqmlengine_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_QQmlImport : public QQmlDataTest { Q_OBJECT +public: + tst_QQmlImport(); + private slots: void importPathOrder(); void testDesignerSupported(); @@ -56,6 +59,8 @@ private slots: void cleanup(); void envResourceImportPath(); void preferResourcePath(); + void invalidFileImport_data(); + void invalidFileImport(); }; void tst_QQmlImport::cleanup() @@ -101,6 +106,36 @@ void tst_QQmlImport::preferResourcePath() QCOMPARE(o->objectName(), "right"); } +void tst_QQmlImport::invalidFileImport_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<QString>("import"); + QTest::addRow("file absolute") + << QStringLiteral("absoluteImport.qml") + << QStringLiteral("/foo/bar/baz"); + QTest::addRow("resource absolute") + << QStringLiteral("absoluteResourceImport.qml") + << QStringLiteral(":/absolute/resource/path"); + QTest::addRow("resource relative") + << QStringLiteral("relativeResourceImport.qml") + << QStringLiteral(":relative/resource/path"); +} + +void tst_QQmlImport::invalidFileImport() +{ + QFETCH(QString, file); + QFETCH(QString, import); + + QQmlEngine engine; + + QQmlComponent component(&engine, testFileUrl(file)); + QVERIFY(component.isError()); + QVERIFY(component.errorString().contains( + QStringLiteral("\"%1\" is not a valid import URL. " + "You can pass relative paths or URLs with schema, " + "but not absolute paths or resource paths.").arg(import))); +} + void tst_QQmlImport::testDesignerSupported() { QQuickView *window = new QQuickView(); @@ -125,7 +160,7 @@ void tst_QQmlImport::testDesignerSupported() QVERIFY(window->errors().isEmpty()); QString warningString("%1:30:1: module does not support the designer \"MyPluginUnsupported\" \n import MyPluginUnsupported 1.0\r \n ^ "); -#if !defined(Q_OS_WIN) && !defined(Q_OS_ANDROID) +#if !defined(Q_OS_WIN) warningString.remove('\r'); #endif warningString = warningString.arg(testFileUrl("testfile_unsupported.qml").toString()); @@ -175,6 +210,11 @@ void tst_QQmlImport::uiFormatLoading() delete test; } +tst_QQmlImport::tst_QQmlImport() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_QQmlImport::importPathOrder() { #ifdef Q_OS_ANDROID @@ -302,7 +342,7 @@ void tst_QQmlImport::interceptQmldir() QQmlComponent component(&engine); component.loadUrl(testFileUrl("interceptQmldir.qml")); - QVERIFY(component.isReady()); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); } @@ -316,7 +356,7 @@ void tst_QQmlImport::singletonVersionResolution() // Singleton with higher version is simply ignored when importing lower version of plugin QQmlComponent component(&engine); component.loadUrl(testFileUrl("QTBUG-77102/main.0.9.qml")); - QVERIFY(component.isReady()); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); } @@ -325,7 +365,7 @@ void tst_QQmlImport::singletonVersionResolution() QQmlComponent component(&engine); QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression {".*ReferenceError: MySettings is not defined$"} ); component.loadUrl(testFileUrl("QTBUG-77102/main.0.9.fail.qml")); - QVERIFY(component.isReady()); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); } @@ -333,7 +373,7 @@ void tst_QQmlImport::singletonVersionResolution() // unless a version which is high enough is imported QQmlComponent component(&engine); component.loadUrl(testFileUrl("QTBUG-77102/main.1.0.qml")); - QVERIFY(component.isReady()); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); auto item = qobject_cast<QQuickItem*>(obj.get()); @@ -343,7 +383,7 @@ void tst_QQmlImport::singletonVersionResolution() // or when there is no number because we are importing from a path QQmlComponent component(&engine); component.loadUrl(testFileUrl("QTBUG-77102/main.nonumber.qml")); - QVERIFY(component.isReady()); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); QScopedPointer<QObject> obj(component.create()); QVERIFY(!obj.isNull()); auto item = qobject_cast<QQuickItem*>(obj.get()); @@ -357,9 +397,10 @@ void tst_QQmlImport::removeDynamicPlugin() QQmlEngine engine; { // Load something that adds a dynamic plugin - QQmlComponent component(&engine); - component.setData(QByteArray("import QtTest 1.0; TestResult{}"), QUrl()); - QVERIFY(component.isReady()); + QQmlComponent component(&engine, testFileUrl("importQtQuickTooling.qml")); + // Make sure to use something other than QtTest here, since the !plugins.isEmpty() + // check will fail if we do. + QVERIFY2(component.isReady(), qPrintable(component.errorString())); } QQmlImportDatabase *imports = &QQmlEnginePrivate::get(&engine)->importDatabase; const QStringList &plugins = imports->dynamicPlugins(); @@ -449,7 +490,7 @@ void tst_QQmlImport::importDependenciesPrecedence() engine.addImportPath(dataDirectory()); QQmlComponent component(&engine, testFile("dependencies.qml")); - QVERIFY(component.isReady()); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); QScopedPointer<QObject> instance(component.create()); QVERIFY(!instance.isNull()); diff --git a/tests/auto/qml/qqmlincubator/CMakeLists.txt b/tests/auto/qml/qqmlincubator/CMakeLists.txt index 34f794b7d9..b2ade30c39 100644 --- a/tests/auto/qml/qqmlincubator/CMakeLists.txt +++ b/tests/auto/qml/qqmlincubator/CMakeLists.txt @@ -12,20 +12,22 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlincubator SOURCES - ../../shared/util.cpp ../../shared/util.h testtypes.cpp testtypes.h tst_qqmlincubator.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::Network Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmlincubator) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp index 7784afd35b..5850ddfa54 100644 --- a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp +++ b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp @@ -38,16 +38,16 @@ #include <QQmlProperty> #include <QQmlComponent> #include <QQmlIncubator> -#include "../../shared/util.h" #include <private/qjsvalue_p.h> #include <private/qqmlincubator_p.h> #include <private/qqmlobjectcreator_p.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlincubator : public QQmlDataTest { Q_OBJECT public: - tst_qqmlincubator() {} + tst_qqmlincubator() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; diff --git a/tests/auto/qml/qqmlinfo/CMakeLists.txt b/tests/auto/qml/qqmlinfo/CMakeLists.txt index 4d234e8ce0..3020b84c59 100644 --- a/tests/auto/qml/qqmlinfo/CMakeLists.txt +++ b/tests/auto/qml/qqmlinfo/CMakeLists.txt @@ -12,19 +12,21 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlinfo SOURCES - ../../shared/util.cpp ../../shared/util.h attached.cpp attached.h tst_qqmlinfo.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmlinfo) +endif() + #### Keys ignored in scope 1:.:.:qqmlinfo.pro:<TRUE>: # QML_IMPORT_MAJOR_VERSION = "1" # QML_IMPORT_NAME = "org.qtproject.Test" @@ -47,4 +49,4 @@ set_target_properties(tst_qqmlinfo PROPERTIES QT_QML_MODULE_URI org.qtproject.Test ) -qt6_qml_type_registration(tst_qqmlinfo) +_qt_internal_qml_type_registration(tst_qqmlinfo) diff --git a/tests/auto/qml/qqmlinfo/tst_qqmlinfo.cpp b/tests/auto/qml/qqmlinfo/tst_qqmlinfo.cpp index 7b7a12ee1b..e7e7d3be76 100644 --- a/tests/auto/qml/qqmlinfo/tst_qqmlinfo.cpp +++ b/tests/auto/qml/qqmlinfo/tst_qqmlinfo.cpp @@ -33,7 +33,7 @@ #include <QTimer> #include <QQmlContext> #include <qqmlinfo.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include "attached.h" @@ -41,7 +41,7 @@ class tst_qqmlinfo : public QQmlDataTest { Q_OBJECT public: - tst_qqmlinfo() {} + tst_qqmlinfo() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void qmlObject(); diff --git a/tests/auto/qml/qqmlinstantiator/CMakeLists.txt b/tests/auto/qml/qqmlinstantiator/CMakeLists.txt index b7d967ca9f..ffe3a10b17 100644 --- a/tests/auto/qml/qqmlinstantiator/CMakeLists.txt +++ b/tests/auto/qml/qqmlinstantiator/CMakeLists.txt @@ -12,17 +12,15 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlinstantiator SOURCES - ../../shared/util.cpp ../../shared/util.h stringmodel.h tst_qqmlinstantiator.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlModelsPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlinstantiator/data/activeModelChangeInteraction.qml b/tests/auto/qml/qqmlinstantiator/data/activeModelChangeInteraction.qml new file mode 100644 index 0000000000..2797566ad2 --- /dev/null +++ b/tests/auto/qml/qqmlinstantiator/data/activeModelChangeInteraction.qml @@ -0,0 +1,39 @@ +import QtQuick 2.15 +import QtQml.Models 2.15 + +Item { + id: root + property int instanceCount: 0 + property alias active: instantiator.active + + ListModel { + id: listmodel + + dynamicRoles: true + } + + Component.onCompleted: { + listmodel.insert(listmodel.count, {name: "one"}) + listmodel.insert(listmodel.count, {name: "two"}) + listmodel.insert(listmodel.count, {name: "three"}) + } + + Instantiator { + id: instantiator + + active: false + + model: listmodel + + delegate: Text { + width: 100 + height: 20 + + text: name + + Component.onCompleted: ++root.instanceCount + } + + } +} + diff --git a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp index 84e08c471a..3524d5de64 100644 --- a/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp +++ b/tests/auto/qml/qqmlinstantiator/tst_qqmlinstantiator.cpp @@ -34,19 +34,23 @@ #include <QtQmlModels/private/qqmlinstantiator_p.h> #include <QtQml/qqmlcontext.h> #include <QtQml/qqmlincubator.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include "stringmodel.h" class tst_qqmlinstantiator: public QQmlDataTest { Q_OBJECT +public: + tst_qqmlinstantiator(); + private slots: void createNone(); void createSingle(); void createMultiple(); void stringModel(); void activeProperty(); + void activeModelChangeInteraction(); void intModelChange(); void createAndRemove(); @@ -54,11 +58,17 @@ private slots: void asynchronous(); }; +tst_qqmlinstantiator::tst_qqmlinstantiator() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_qqmlinstantiator::createNone() { QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("createNone.qml")); - QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create()); + QScopedPointer<QObject> o(component.create()); + QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(o.data()); QVERIFY(instantiator != nullptr); QCOMPARE(instantiator->isActive(), true); QCOMPARE(instantiator->count(), 0); @@ -70,7 +80,8 @@ void tst_qqmlinstantiator::createSingle() { QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("createSingle.qml")); - QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create()); + QScopedPointer<QObject> o(component.create()); + QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(o.data()); QVERIFY(instantiator != nullptr); QCOMPARE(instantiator->isActive(), true); QCOMPARE(instantiator->count(), 1); @@ -87,7 +98,8 @@ void tst_qqmlinstantiator::createMultiple() { QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("createMultiple.qml")); - QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create()); + QScopedPointer<QObject> o(component.create()); + QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(o.data()); QVERIFY(instantiator != nullptr); QCOMPARE(instantiator->isActive(), true); QCOMPARE(instantiator->count(), 10); @@ -105,7 +117,8 @@ void tst_qqmlinstantiator::stringModel() { QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("stringModel.qml")); - QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create()); + QScopedPointer<QObject> o(component.create()); + QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(o.data()); QVERIFY(instantiator != nullptr); QCOMPARE(instantiator->isActive(), true); QCOMPARE(instantiator->count(), 4); @@ -122,7 +135,8 @@ void tst_qqmlinstantiator::activeProperty() { QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("inactive.qml")); - QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create()); + QScopedPointer<QObject> o(component.create()); + QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(o.data()); QVERIFY(instantiator != nullptr); QSignalSpy activeSpy(instantiator, SIGNAL(activeChanged())); QSignalSpy countSpy(instantiator, SIGNAL(countChanged())); @@ -153,11 +167,32 @@ void tst_qqmlinstantiator::activeProperty() QCOMPARE(object->property("idx").toInt(), 0); } +void tst_qqmlinstantiator::activeModelChangeInteraction() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("activeModelChangeInteraction.qml")); + QScopedPointer<QObject> root(component.create()); + QVERIFY(root); + + // If the instantiator is inactive, a model change does not lead to items being loaded + bool ok = false; + int count = root->property("instanceCount").toInt(&ok); + QVERIFY(ok); + QCOMPARE(count, 0); + + // When turning the instantiator active, it will however reflect the model + root->setProperty("active", true); + count = root->property("instanceCount").toInt(&ok); + QVERIFY(ok); + QCOMPARE(count, 3); +} + void tst_qqmlinstantiator::intModelChange() { QQmlEngine engine; QQmlComponent component(&engine, testFileUrl("createMultiple.qml")); - QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(component.create()); + QScopedPointer<QObject> o(component.create()); + QQmlInstantiator *instantiator = qobject_cast<QQmlInstantiator*>(o.data()); QVERIFY(instantiator != nullptr); QSignalSpy activeSpy(instantiator, SIGNAL(activeChanged())); QSignalSpy countSpy(instantiator, SIGNAL(countChanged())); @@ -193,7 +228,7 @@ void tst_qqmlinstantiator::createAndRemove() QScopedPointer<StringModel> model {new StringModel("model1")}; qmlRegisterSingletonInstance("Test", 1, 0, "Model1", model.get()); QQmlComponent component(&engine, testFileUrl("createAndRemove.qml")); - QObject *rootObject = component.create(); + QScopedPointer<QObject> rootObject(component.create()); QVERIFY(rootObject != nullptr); QQmlInstantiator *instantiator = diff --git a/tests/auto/qml/qqmlitemmodels/CMakeLists.txt b/tests/auto/qml/qqmlitemmodels/CMakeLists.txt index 5246638739..7955eeba7b 100644 --- a/tests/auto/qml/qqmlitemmodels/CMakeLists.txt +++ b/tests/auto/qml/qqmlitemmodels/CMakeLists.txt @@ -12,15 +12,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlitemmodels SOURCES - ../../shared/util.cpp ../../shared/util.h qtestmodel.h testtypes.h tst_qqmlitemmodels.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::Qml + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlitemmodels/data/modelindex.qml b/tests/auto/qml/qqmlitemmodels/data/modelindex.qml index 0d6e3624cb..2756f04120 100644 --- a/tests/auto/qml/qqmlitemmodels/data/modelindex.qml +++ b/tests/auto/qml/qqmlitemmodels/data/modelindex.qml @@ -1,3 +1,4 @@ +import QtQml 2.0 import Test 1.0 ItemModelsTest { diff --git a/tests/auto/qml/qqmlitemmodels/data/persistentmodelindex.qml b/tests/auto/qml/qqmlitemmodels/data/persistentmodelindex.qml index 13037065a6..85987bdcac 100644 --- a/tests/auto/qml/qqmlitemmodels/data/persistentmodelindex.qml +++ b/tests/auto/qml/qqmlitemmodels/data/persistentmodelindex.qml @@ -1,3 +1,4 @@ +import QtQml 2.0 import Test 1.0 ItemModelsTest { diff --git a/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp b/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp index 21bde0dd14..6fb86b98d5 100644 --- a/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp +++ b/tests/auto/qml/qqmlitemmodels/tst_qqmlitemmodels.cpp @@ -31,7 +31,7 @@ #include <QQmlComponent> #include <QDebug> #include <QStringListModel> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include "testtypes.h" #include "qtestmodel.h" @@ -45,7 +45,7 @@ class tst_qqmlitemmodels : public QQmlDataTest Q_OBJECT public: - tst_qqmlitemmodels() {} + tst_qqmlitemmodels() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; diff --git a/tests/auto/qml/qqmljsscope/BLACKLIST b/tests/auto/qml/qqmljsscope/BLACKLIST new file mode 100644 index 0000000000..1cae50360f --- /dev/null +++ b/tests/auto/qml/qqmljsscope/BLACKLIST @@ -0,0 +1,3 @@ +# QTBUG-100020 +[orderedBindings] +android diff --git a/tests/auto/qml/qqmllanguage/CMakeLists.txt b/tests/auto/qml/qqmllanguage/CMakeLists.txt index e7fa05d23e..08d747b818 100644 --- a/tests/auto/qml/qqmllanguage/CMakeLists.txt +++ b/tests/auto/qml/qqmllanguage/CMakeLists.txt @@ -12,18 +12,15 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmllanguage SOURCES - ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h - ../../shared/util.cpp ../../shared/util.h testtypes.cpp testtypes.h tst_qqmllanguage.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::Network Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) @@ -67,4 +64,4 @@ set_target_properties(tst_qqmllanguage PROPERTIES QT_QML_MODULE_URI StaticTest ) -qt6_qml_type_registration(tst_qqmllanguage) +_qt_internal_qml_type_registration(tst_qqmllanguage) diff --git a/tests/auto/qml/qqmllanguage/data/Broken.qml b/tests/auto/qml/qqmllanguage/data/Broken.qml new file mode 100644 index 0000000000..e1b61f31f4 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/Broken.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + notThere: 5 +} diff --git a/tests/auto/qml/qqmllanguage/data/ComponentType.qml b/tests/auto/qml/qqmllanguage/data/ComponentType.qml new file mode 100644 index 0000000000..e8addde1c4 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/ComponentType.qml @@ -0,0 +1,8 @@ +import QtQml + +Component { + id: componentRoot + QtObject { + objectName: "enclosed" + } +} diff --git a/tests/auto/qml/qqmllanguage/data/GroupFailureInner.qml b/tests/auto/qml/qqmllanguage/data/GroupFailureInner.qml new file mode 100644 index 0000000000..7972cc9683 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/GroupFailureInner.qml @@ -0,0 +1,2 @@ +import QtQml +QtObject { property url u } diff --git a/tests/auto/qml/qqmllanguage/data/GroupFailureOuter.qml b/tests/auto/qml/qqmllanguage/data/GroupFailureOuter.qml new file mode 100644 index 0000000000..2a34a29789 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/GroupFailureOuter.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property GroupFailureInner b +} diff --git a/tests/auto/qml/qqmllanguage/data/MyRectangle.qml b/tests/auto/qml/qqmllanguage/data/MyRectangle.qml new file mode 100644 index 0000000000..4d5e7c6c8d --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/MyRectangle.qml @@ -0,0 +1,10 @@ +import QtQuick + +Item { + property alias rectangle1AnchorsleftMargin: rectangle1.anchors.leftMargin + + Rectangle { + id: rectangle1 + anchors.leftMargin: 250 + } +} diff --git a/tests/auto/qml/qqmllanguage/data/SignalInlineComponentArg.qml b/tests/auto/qml/qqmllanguage/data/SignalInlineComponentArg.qml new file mode 100644 index 0000000000..0424ac1534 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/SignalInlineComponentArg.qml @@ -0,0 +1,21 @@ +import QtQuick + +Item { + component Abc: Item { + property string success + } + + signal canYouFeelIt(arg1: Abc) + property Abc someAbc: Abc { + success: "Signal was called" + } + property string success: "Signal not called yet" + + Component.onCompleted: { + canYouFeelIt(someAbc); + } + + onCanYouFeelIt: (arg) => { + success = arg.success + } +} diff --git a/tests/auto/qml/qqmllanguage/data/alias.15.qml b/tests/auto/qml/qqmllanguage/data/alias.15.qml index 5f3de9c83e..7e362d8823 100644 --- a/tests/auto/qml/qqmllanguage/data/alias.15.qml +++ b/tests/auto/qml/qqmllanguage/data/alias.15.qml @@ -9,4 +9,25 @@ Item { Item { id: symbol } + + Rectangle { + id: txtElevationValue + + property Rectangle background: Rectangle { } + + state: "ValidatorInvalid" + + states: [ + State { + name: "ValidatorInvalid" + PropertyChanges { + target: txtElevationValue + background.border.color: "red" // this line caused the segfault in qtbug107795 + } + }, + State { + name: "ValidatorAcceptable" + } + ] + } } diff --git a/tests/auto/qml/qqmllanguage/data/alias.15a.qml b/tests/auto/qml/qqmllanguage/data/alias.15a.qml new file mode 100644 index 0000000000..ba8097c997 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.15a.qml @@ -0,0 +1,12 @@ +import QtQuick 2.15 + +Item { + id: root + + property alias symbol: symbol + symbol.layer.enabled: true + + Item { + id: symbol + } +} diff --git a/tests/auto/qml/qqmllanguage/data/alias.19.qml b/tests/auto/qml/qqmllanguage/data/alias.19.qml new file mode 100644 index 0000000000..a96c0c694d --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/alias.19.qml @@ -0,0 +1,11 @@ +import QtQuick + +Item { + id: myThing + width: 1920 + + MyRectangle { + rectangle1AnchorsleftMargin: myThing.width / 2 + Component.onCompleted: myThing.height = rectangle1AnchorsleftMargin + } +} diff --git a/tests/auto/qml/qqmllanguage/data/ambiguousBinding/TestCase.qml b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/TestCase.qml new file mode 100644 index 0000000000..c76d2b679e --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/TestCase.qml @@ -0,0 +1,6 @@ +import QtQml 2.15 +import QtTest 1.0 + +QtObject { + component Comp: QtObject {} +} diff --git a/tests/auto/qml/qqmllanguage/data/ambiguousBinding/ambiguousContainingType.qml b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/ambiguousContainingType.qml new file mode 100644 index 0000000000..765dc91fe1 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/ambiguousBinding/ambiguousContainingType.qml @@ -0,0 +1,3 @@ +import QtQml 2.15 + +TestCase {} diff --git a/tests/auto/qml/qqmllanguage/data/asBroken.qml b/tests/auto/qml/qqmllanguage/data/asBroken.qml new file mode 100644 index 0000000000..381a012df6 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/asBroken.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + id: self + property var selfAsBroken: self as Broken +} diff --git a/tests/auto/qml/qqmllanguage/data/badGroupedProperty.qml b/tests/auto/qml/qqmllanguage/data/badGroupedProperty.qml new file mode 100644 index 0000000000..1b8ba61725 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/badGroupedProperty.qml @@ -0,0 +1,10 @@ +import QtQml + +QtObject { + id: testItem + property rect rect + onComplete { + rect.x: 2 + rect.width: 22 + } +} diff --git a/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl.qml b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl.qml new file mode 100644 index 0000000000..44fbd03354 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl.qml @@ -0,0 +1,10 @@ +import QtQuick +Item { + id: root + Component { + id: accessibleNormal + Item {} + } + property alias accessibleNormalUrl: accessibleNormal.url + property url urlClone: root.accessibleNormalUrl // crashes qml utility +} diff --git a/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl2.qml b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl2.qml new file mode 100644 index 0000000000..cfdec5e39b --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/bindingAliasToComponentUrl2.qml @@ -0,0 +1,11 @@ +import QtQuick +Item { + id: root + Component { + id: accessibleNormal + ComponentType { + id: inaccessibleNormal + } + } + property alias accessibleNormalProgress: accessibleNormal.progress +} diff --git a/tests/auto/qml/qqmllanguage/data/componentMix.qml b/tests/auto/qml/qqmllanguage/data/componentMix.qml new file mode 100644 index 0000000000..0edc997484 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/componentMix.qml @@ -0,0 +1,18 @@ +import QtQml + +QtObject { + component View: QtObject { + default property Component delegate + } + + component Things : QtObject { + property QtObject view: View { delegate: QtObject {} } + } + + component Delegated : View { + delegate: QtObject {} + } + + property Things things: Things {} + property Delegated delegated: Delegated {} +} diff --git a/tests/auto/qml/qqmllanguage/data/foreignExtended.qml b/tests/auto/qml/qqmllanguage/data/foreignExtended.qml index 4863e0d567..b01af6d229 100644 --- a/tests/auto/qml/qqmllanguage/data/foreignExtended.qml +++ b/tests/auto/qml/qqmllanguage/data/foreignExtended.qml @@ -5,12 +5,17 @@ QtObject { property Foreign foreign: Foreign { objectName: "foreign" } - property Extended extended: Extended {} + property Extended extended: Extended { + objectName: "extended" + property int changeCount: 0 + onExtensionChanged: ++changeCount + } property ForeignExtended foreignExtended: ForeignExtended { objectName: "foreignExtended" } property int extendedBase: extended.base + property int extendedChangeCount: extended.changeCount property int extendedInvokable: extended.invokable() property int extendedSlot: extended.slot() diff --git a/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt b/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt index e399799fe9..758be7feae 100644 --- a/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt +++ b/tests/auto/qml/qqmllanguage/data/fuzzed.1.errors.txt @@ -1,2 +1 @@ -2:8:Cannot assign to non-existent property "_G" - +2:11:Non-existent attached object diff --git a/tests/auto/qml/qqmllanguage/data/groupFailure.qml b/tests/auto/qml/qqmllanguage/data/groupFailure.qml new file mode 100644 index 0000000000..e8f8999482 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/groupFailure.qml @@ -0,0 +1,5 @@ +import QtQml + +GroupFailureOuter { + b.u: null +} diff --git a/tests/auto/qml/qqmllanguage/data/jittedAsCast.qml b/tests/auto/qml/qqmllanguage/data/jittedAsCast.qml new file mode 100644 index 0000000000..e1798a5d35 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/jittedAsCast.qml @@ -0,0 +1,15 @@ +import QtQml + +QtObject { + property QtObject obj: Timer { + interval: 1 + running: true + repeat: true + onTriggered: { + if (++interval === 10) + running = false + } + } + property bool running: (obj as Timer).running + property int interval: (obj as Timer).interval +} diff --git a/tests/auto/qml/qqmllanguage/data/sameNameAliasProperty.qml b/tests/auto/qml/qqmllanguage/data/sameNameAliasProperty.qml new file mode 100644 index 0000000000..288fd618a6 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/sameNameAliasProperty.qml @@ -0,0 +1,7 @@ +import QtQml 2.15 + +QtObject { + id: root + property int a + property alias a: root.a +} diff --git a/tests/auto/qml/qqmllanguage/data/sameNamePropertyAlias.qml b/tests/auto/qml/qqmllanguage/data/sameNamePropertyAlias.qml new file mode 100644 index 0000000000..bb26ba4396 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/sameNamePropertyAlias.qml @@ -0,0 +1,7 @@ +import QtQml 2.15 + +QtObject { + id: root + property alias a: root.a + property int a +} diff --git a/tests/auto/qml/qqmllanguage/data/signalInlineComponentArg1.qml b/tests/auto/qml/qqmllanguage/data/signalInlineComponentArg1.qml new file mode 100644 index 0000000000..e20710edd9 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/signalInlineComponentArg1.qml @@ -0,0 +1,30 @@ +import QtQuick + +// this file performs two tests: first, using a signal with a inline component from another file +// and second, calling the signal from another file using an inline component from another file + +Item { + signal canYouFeelIt(arg1:SignalInlineComponentArg.Abc) + + property SignalInlineComponentArg.Abc someAbc: SignalInlineComponentArg.Abc { + success: "Own signal was called with component from another file" + } + + property SignalInlineComponentArg fromAnotherFile: SignalInlineComponentArg {} + + // success of own signal call with parameter from another file + property string successFromOwnSignal: "Signal not called yet" + // makes it easier to test + property string successFromSignalFromFile: fromAnotherFile.success + + Component.onCompleted: { + canYouFeelIt(someAbc); + fromAnotherFile.someAbc.success = "Signal was called from another file" + fromAnotherFile.canYouFeelIt(fromAnotherFile.someAbc) + } + + onCanYouFeelIt: (arg) => { + successFromOwnSignal = arg.success + } +} + diff --git a/tests/auto/qml/qqmllanguage/data/thisInArrow.qml b/tests/auto/qml/qqmllanguage/data/thisInArrow.qml new file mode 100644 index 0000000000..7dd19782e6 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/thisInArrow.qml @@ -0,0 +1,39 @@ +import QtQml + +QtObject { + id: root + + property int width: 43 + Component.onCompleted: () => { console.log(this.width); } + + property var arrow: () => { return this; } + property var func: function() { return this; } + + property QtObject child: QtObject { + property var aa; + property var ff; + + Component.onCompleted: { + root.arrowResult = root.arrow(); + root.funcResult = root.func(); + + var a = root.arrow; + root.aResult = a(); + var f = root.func; + root.fResult = f(); + + aa = a; + root.aaResult = aa(); + + ff = f; + root.ffResult = ff(); + } + } + + property var arrowResult + property var funcResult + property var aResult + property var fResult + property var aaResult + property var ffResult +} diff --git a/tests/auto/qml/qqmllanguage/data/uncreatableAttached.qml b/tests/auto/qml/qqmllanguage/data/uncreatableAttached.qml new file mode 100644 index 0000000000..4a861ea075 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/uncreatableAttached.qml @@ -0,0 +1,8 @@ +import QtQml +import ABC + +QtObject { + id: testItem + objectName: "00000000000000000000" + ItemAttached.attachedName: "111111111" +} diff --git a/tests/auto/qml/qqmllanguage/data/variantListConversion.qml b/tests/auto/qml/qqmllanguage/data/variantListConversion.qml index 334bf17393..19760a64ee 100644 --- a/tests/auto/qml/qqmllanguage/data/variantListConversion.qml +++ b/tests/auto/qml/qqmllanguage/data/variantListConversion.qml @@ -1,7 +1,8 @@ import Test +import QtQml Foo { a.a: 12 b.a: 13 - fooProperty: [a, b] + fooProperty: [a, b, Component] } diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index fd541fd36a..92e24bc332 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -177,7 +177,7 @@ void EnumSupportingCustomParser::verifyBindings(const QQmlRefPointer<QV4::Execut return; } - if (binding->type != QV4::CompiledData::Binding::Type_Script) { + if (binding->type() != QV4::CompiledData::Binding::Type_Script) { error(binding, QStringLiteral("Custom parser invoked with the wrong property value. Expected script that evaluates to enum")); return; } diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index 2ffc324cae..e43424c9ca 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -1464,13 +1464,23 @@ public: class Extension : public QObject { Q_OBJECT - Q_PROPERTY(int extension READ extension CONSTANT) + Q_PROPERTY(int extension READ extension WRITE setExtension NOTIFY extensionChanged FINAL) public: Extension(QObject *parent = nullptr) : QObject(parent) {} - int extension() const { return 42; } + int extension() const { return ext; } + void setExtension(int e) { + if (e != ext) { + ext = e; + emit extensionChanged(); + } + } Q_INVOKABLE int invokable() { return 123; } +Q_SIGNALS: + void extensionChanged(); public slots: int slot() { return 456; } +private: + int ext = 42; }; class Extended : public QObject @@ -1566,6 +1576,33 @@ public: int own() const { return 93; } }; +class ExtendedNamespaceByObject : public QObject +{ + Q_OBJECT + QML_ELEMENT + QML_EXTENDED_NAMESPACE(Extension) + + Q_PROPERTY(QString dummy READ dummy CONSTANT) + Q_PROPERTY(int extension READ extension WRITE setExtension NOTIFY extensionChanged) + + int m_ext = 0; + +public: + ExtendedNamespaceByObject(QObject *parent = nullptr) : QObject(parent) {} + QString dummy() const { return QStringLiteral("dummy"); } + int extension() const { return m_ext; } + void setExtension(int e) + { + if (e != m_ext) { + m_ext = e; + Q_EMIT extensionChanged(); + } + } + +Q_SIGNALS: + void extensionChanged(); +}; + class FactorySingleton : public QObject { Q_OBJECT @@ -1773,6 +1810,60 @@ private: QVariantList mFooProperty; }; +class ItemAttached : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString attachedName READ attachedName WRITE setAttachedName NOTIFY attachedNameChanged) + QML_ELEMENT + QML_ATTACHED(ItemAttached) +public: + ItemAttached(QObject *parent = nullptr) : QObject(parent) {} + + QString attachedName() const { return m_name; } + void setAttachedName(const QString &name) + { + if (name != m_name) { + m_name = name; + emit attachedNameChanged(); + } + } + + static ItemAttached *qmlAttachedProperties(QObject *object) + { + if (object->objectName() != QLatin1String("foo")) { + qWarning("Only foo can have ItemAttached!"); + return nullptr; + } + + return new ItemAttached(object); + } + +signals: + void attachedNameChanged(); + +private: + QString m_name; +}; + +class BindableOnly : public QObject +{ + Q_OBJECT + Q_PROPERTY(QByteArray data READ data WRITE setData BINDABLE dataBindable FINAL) + QML_ELEMENT +public: + BindableOnly(QObject *parent = nullptr) + : QObject(parent) + {} + + QBindable<QByteArray> dataBindable() { return QBindable<QByteArray>(&m_data); } + + QByteArray data() const { return m_data.value(); } + void setData(const QByteArray &newData) { m_data.setValue(newData); } + +private: + QProperty<QByteArray> m_data; +}; + void registerTypes(); #endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index d09f903ccb..047df2f6d0 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -50,11 +50,12 @@ #include <private/qqmlvmemetaobject_p.h> #include <private/qqmlcomponent_p.h> #include <private/qqmltype_p_p.h> +#include <private/qqmlcomponentattached_p.h> +#include <private/qv4debugging_p.h> #include "testtypes.h" -#include "testhttpserver.h" - -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> +#include <QtQuickTestUtils/private/testhttpserver_p.h> #include <deque> @@ -85,6 +86,9 @@ class tst_qqmllanguage : public QQmlDataTest { Q_OBJECT +public: + tst_qqmllanguage(); + private slots: void initTestCase() override; void cleanupTestCase(); @@ -242,6 +246,8 @@ private slots: void deepProperty(); + void groupAssignmentFailure(); + void compositeSingletonProperties(); void compositeSingletonSameEngine(); void compositeSingletonDifferentEngine(); @@ -345,6 +351,7 @@ private slots: void checkURLtoURLObject(); void registerValueTypes(); void extendedNamespace(); + void extendedNamespaceByObject(); void factorySingleton(); void extendedSingleton(); void qtbug_85932(); @@ -363,7 +370,23 @@ private slots: void propertyObserverOnReadonly(); + void propertyAndAliasMustHaveDistinctNames_data(); + void propertyAndAliasMustHaveDistinctNames(); + void variantListConversion(); + void thisInArrowFunction(); + + void jittedAsCast(); + + void ambiguousContainingType(); + void objectAsBroken(); + void componentMix(); + void uncreatableAttached(); + + void bindableOnly(); + void badGroupedProperty(); + void bindingAliasToComponentUrl(); + void signalInlineComponentArg(); private: QQmlEngine engine; @@ -2141,6 +2164,22 @@ void tst_qqmllanguage::aliasProperties() QCOMPARE(subItem->property("y").toInt(), 1); } + // Nested property bindings on group properties that are actually aliases (QTBUG-94983) + { + QQmlComponent component(&engine, testFileUrl("alias.15a.qml")); + VERIFY_ERRORS(0); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QPointer<QObject> subItem = qvariant_cast<QObject*>(object->property("symbol")); + QVERIFY(!subItem.isNull()); + + QPointer<QObject> subSubItem = qvariant_cast<QObject*>(subItem->property("layer")); + + QCOMPARE(subSubItem->property("enabled").value<bool>(), true); + } + // Alias to sub-object with binding (QTBUG-57041) { // This is shold *not* crash. @@ -2218,6 +2257,16 @@ void tst_qqmllanguage::aliasProperties() QQmlComponent component(&engine, testFileUrl("alias.18.qml")); VERIFY_ERRORS("alias.18.errors.txt"); } + + // Binding on deep alias + { + QQmlComponent component(&engine, testFileUrl("alias.19.qml")); + VERIFY_ERRORS(0); + + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + QCOMPARE(object->property("height").toInt(), 960); + } } // QTBUG-13374 Test that alias properties and signals can coexist @@ -3730,6 +3779,11 @@ void tst_qqmllanguage::uncreatableTypesAsProperties() QVERIFY(!object.isNull()); } +tst_qqmllanguage::tst_qqmllanguage() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_qqmllanguage::initTestCase() { QQmlDataTest::initTestCase(); @@ -4355,6 +4409,17 @@ void tst_qqmllanguage::deepProperty() QCOMPARE(font.family(), QStringLiteral("test")); } +void tst_qqmllanguage::groupAssignmentFailure() +{ + auto ep = std::make_unique<QQmlEngine>(); + QTest::ignoreMessage(QtMsgType::QtWarningMsg, QRegularExpression(".*Invalid property assignment: url expected - Assigning null to incompatible properties in QML is deprecated. This will become a compile error in future versions of Qt..*")); + QQmlComponent component(ep.get(), testFileUrl("groupFailure.qml")); + QScopedPointer<QObject> o(component.create()); + QVERIFY(!o); + ep.reset(); + // ~QQmlComponent should not crash here +} + // Tests that the implicit import has lowest precedence, in the case where // there are conflicting types and types only found in the local import. // Tests that just check one (or the root) type are in ::importsOrder @@ -5502,9 +5567,20 @@ void tst_qqmllanguage::extendedForeignTypes() QScopedPointer<QObject> o(component.create()); QVERIFY(!o.isNull()); + QObject *extended = o->property("extended").value<QObject *>(); + QVERIFY(extended); + QSignalSpy extensionChangedSpy(extended, SIGNAL(extensionChanged())); + QCOMPARE(o->property("extendedBase").toInt(), 43); QCOMPARE(o->property("extendedExtension").toInt(), 42); QCOMPARE(o->property("foreignExtendedExtension").toInt(), 42); + + QCOMPARE(extensionChangedSpy.count(), 0); + extended->setProperty("extension", 44); + QCOMPARE(extensionChangedSpy.count(), 1); + QCOMPARE(o->property("extendedChangeCount").toInt(), 1); + QCOMPARE(o->property("extendedExtension").toInt(), 44); + QCOMPARE(o->property("foreignObjectName").toString(), QLatin1String("foreign")); QCOMPARE(o->property("foreignExtendedObjectName").toString(), QLatin1String("foreignExtended")); QCOMPARE(o->property("extendedInvokable").toInt(), 123); @@ -6096,6 +6172,22 @@ void tst_qqmllanguage::extendedNamespace() QCOMPARE(obj->property("fromExtension").toInt(), 9); } +void tst_qqmllanguage::extendedNamespaceByObject() +{ + QQmlEngine engine; + QQmlComponent c(&engine); + c.setData("import StaticTest\n" + "import QtQml\n" + "ExtendedNamespaceByObject {\n" + " extension: 10\n" + "}", QUrl()); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> obj(c.create()); + QVERIFY(!obj.isNull()); + + QCOMPARE(obj->property("extension").toInt(), 10); +} + void tst_qqmllanguage::factorySingleton() { QQmlEngine engine; @@ -6294,8 +6386,23 @@ void tst_qqmllanguage::bareInlineComponent() QVERIFY(tab1Found); } +struct DummyDebugger : public QV4::Debugging::Debugger +{ + bool pauseAtNextOpportunity() const final { return false; } + void maybeBreakAtInstruction() final { } + void enteringFunction() final { } + void leavingFunction(const QV4::ReturnedValue &) final { } + void aboutToThrow() final { } +}; + void tst_qqmllanguage::hangOnWarning() { + QQmlEngine engine; + + // A debugger prevents the disk cache. + // If we load the file from disk cache we don't parse it and we don't see the warning. + engine.handle()->setDebugger(new DummyDebugger); + QTest::ignoreMessage(QtWarningMsg, qPrintable(QStringLiteral("%1:3 : Ignored annotation") .arg(testFileUrl("hangOnWarning.qml").toString()))); @@ -6355,6 +6462,26 @@ void tst_qqmllanguage::propertyObserverOnReadonly() QCOMPARE(o->property("height").toDouble(), 54.2); } +void tst_qqmllanguage::propertyAndAliasMustHaveDistinctNames_data() +{ + QTest::addColumn<QString>("fileName"); + QTest::addColumn<QString>("error"); + + QTest::addRow("sameNamePropertyAlias") << "sameNamePropertyAlias.qml" << "Property duplicates alias name"; + QTest::addRow("sameNameAliasProperty") << "sameNameAliasProperty.qml" << "Alias has same name as existing property"; +} + +void tst_qqmllanguage::propertyAndAliasMustHaveDistinctNames() +{ + QFETCH(QString, fileName); + QFETCH(QString, error); + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl(fileName)); + QVERIFY(!c.isReady()); + auto actualError = c.errorString(); + QVERIFY2(actualError.contains(error), qPrintable(actualError)); +} + void tst_qqmllanguage::variantListConversion() { QQmlEngine engine; @@ -6365,11 +6492,181 @@ void tst_qqmllanguage::variantListConversion() Foo *foo = qobject_cast<Foo *>(o.data()); QVERIFY(foo); const QVariantList list = foo->getList(); - QCOMPARE(list.length(), 2); + QCOMPARE(list.length(), 3); const Large l0 = qvariant_cast<Large>(list.at(0)); QCOMPARE(l0.a, 12ull); const Large l1 = qvariant_cast<Large>(list.at(1)); QCOMPARE(l1.a, 13ull); + const QObject *attached = qvariant_cast<QObject *>(list.at(2)); + QVERIFY(attached); + QCOMPARE(attached->metaObject(), &QQmlComponentAttached::staticMetaObject); +} + +void tst_qqmllanguage::thisInArrowFunction() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("thisInArrow.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + + QTest::ignoreMessage(QtDebugMsg, "43"); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + + QCOMPARE(qvariant_cast<QObject *>(o->property("arrowResult")), o.data()); + QCOMPARE(qvariant_cast<QObject *>(o->property("funcResult")), o.data()); + QCOMPARE(qvariant_cast<QObject *>(o->property("aResult")), o.data()); + QCOMPARE(qvariant_cast<QObject *>(o->property("aaResult")), o.data()); + + QCOMPARE(qvariant_cast<QObject *>(o->property("fResult")), nullptr); + QCOMPARE(o->property("fResult").metaType(), QMetaType::fromType<QJSValue>()); + QVERIFY(qvariant_cast<QJSValue>(o->property("fResult")).isObject()); + + QObject *child = qvariant_cast<QObject *>(o->property("child")); + QVERIFY(child != nullptr); + QCOMPARE(qvariant_cast<QObject *>(o->property("ffResult")), child); +} + +void tst_qqmllanguage::jittedAsCast() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("jittedAsCast.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QCOMPARE(o->property("running").toBool(), true); + QTRY_COMPARE(o->property("running").toBool(), false); + QCOMPARE(o->property("interval").toInt(), 10); +} + +void tst_qqmllanguage::ambiguousContainingType() +{ + // Need to do it twice, so that we load from disk cache the second time. + for (int i = 0; i < 2; ++i) { + QQmlEngine engine; + + // Should not crash when loading the type + QQmlComponent c(&engine, testFileUrl("ambiguousBinding/ambiguousContainingType.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + } +} + +void tst_qqmllanguage::objectAsBroken() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("asBroken.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + QVariant selfAsBroken = o->property("selfAsBroken"); + QVERIFY(selfAsBroken.isValid()); + QCOMPARE(selfAsBroken.metaType(), QMetaType::fromType<std::nullptr_t>()); + + QQmlComponent b(&engine, testFileUrl("Broken.qml")); + QVERIFY(b.isError()); +} + +void tst_qqmllanguage::componentMix() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("componentMix.qml")); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + QObject *things = qvariant_cast<QObject *>(o->property("things")); + QVERIFY(things); + QObject *delegated = qvariant_cast<QObject *>(o->property("delegated")); + QVERIFY(delegated); + QObject *view = qvariant_cast<QObject *>(things->property("view")); + QVERIFY(view); + QObject *delegate = qvariant_cast<QObject *>(view->property("delegate")); + QVERIFY(delegate); + QCOMPARE(delegate->metaObject(), &QQmlComponent::staticMetaObject); + QObject *delegate2 = qvariant_cast<QObject *>(delegated->property("delegate")); + QVERIFY(delegate2); + QCOMPARE(delegate2->metaObject(), &QQmlComponent::staticMetaObject); +} + +void tst_qqmllanguage::uncreatableAttached() +{ + qmlRegisterTypesAndRevisions<ItemAttached>("ABC", 1); + QQmlEngine engine; + const QUrl url = testFileUrl("uncreatableAttached.qml"); + QQmlComponent c(&engine, url); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QTest::ignoreMessage(QtWarningMsg, "Only foo can have ItemAttached!"); + QScopedPointer o(c.create()); + QVERIFY(o.isNull()); + QVERIFY(c.errorString().contains( + QLatin1String("Could not create attached properties object 'ItemAttached'"))); +} + +void tst_qqmllanguage::bindableOnly() +{ + qmlRegisterTypesAndRevisions<BindableOnly>("ABC", 1); + QQmlEngine engine; + + QQmlComponent c(&engine); + c.setData("import ABC\nBindableOnly {\n" + " data: \"sc\" + \"ore\"\n" + " objectName: data\n" + "}", QUrl(u"bindableOnly.qml"_qs)); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + QCOMPARE(o->property("data").value<QByteArray>(), QByteArray("score")); + QCOMPARE(o->objectName(), QStringLiteral("score")); +} + +void tst_qqmllanguage::badGroupedProperty() +{ + QQmlEngine engine; + const QUrl url = testFileUrl("badGroupedProperty.qml"); + QQmlComponent c(&engine, url); + QVERIFY(c.isError()); + QCOMPARE(c.errorString(), + QStringLiteral("%1:6 Cannot assign to non-existent property \"onComplete\"\n") + .arg(url.toString())); +} + +void tst_qqmllanguage::bindingAliasToComponentUrl() +{ + QQmlEngine engine; + { + QQmlComponent component(&engine, testFileUrl("bindingAliasToComponentUrl.qml")); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object); + QCOMPARE(object->property("accessibleNormalUrl"), object->property("urlClone")); + } + { + QQmlComponent component(&engine, testFileUrl("bindingAliasToComponentUrl2.qml")); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + QScopedPointer<QObject> object(component.create()); + QVERIFY(object); + QCOMPARE(object->property("accessibleNormalProgress"), QVariant(1.0)); + } +} + +void tst_qqmllanguage::signalInlineComponentArg() +{ + QQmlEngine engine; + { + QQmlComponent component(&engine, testFileUrl("SignalInlineComponentArg.qml")); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + QScopedPointer<QObject> object(component.create()); + + QCOMPARE(object->property("success"), QStringLiteral("Signal was called")); + } + { + QQmlComponent component(&engine, testFileUrl("signalInlineComponentArg1.qml")); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + QScopedPointer<QObject> object(component.create()); + + QCOMPARE(object->property("successFromOwnSignal"), + QStringLiteral("Own signal was called with component from another file")); + QCOMPARE(object->property("successFromSignalFromFile"), + QStringLiteral("Signal was called from another file")); + } } QTEST_MAIN(tst_qqmllanguage) diff --git a/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp b/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp index b49832499e..9315b2d24d 100644 --- a/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp +++ b/tests/auto/qml/qqmllistcompositor/tst_qqmllistcompositor.cpp @@ -89,15 +89,13 @@ QT_END_NAMESPACE static const C::Group Visible = C::Group(2); static const C::Group Selection = C::Group(3); +constexpr auto VisibleFlag = C::Flag(0x04); +constexpr auto SelectionFlag = C::Flag(0x08); + class tst_qqmllistcompositor : public QObject { Q_OBJECT - enum { - VisibleFlag = 0x04, - SelectionFlag = 0x08 - }; - void populateChange( C::Change &change, int sIndex, int vIndex, int dIndex, int cIndex, int count, int flags, int moveId) { diff --git a/tests/auto/qml/qqmllistmodel/CMakeLists.txt b/tests/auto/qml/qqmllistmodel/CMakeLists.txt index d583dc3b0e..18c247f5b9 100644 --- a/tests/auto/qml/qqmllistmodel/CMakeLists.txt +++ b/tests/auto/qml/qqmllistmodel/CMakeLists.txt @@ -12,10 +12,7 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmllistmodel SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmllistmodel.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui @@ -23,6 +20,7 @@ qt_internal_add_test(tst_qqmllistmodel Qt::QmlModelsPrivate Qt::QmlPrivate Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmllistmodel/data/destroyObject.qml b/tests/auto/qml/qqmllistmodel/data/destroyObject.qml new file mode 100644 index 0000000000..e6b3f33bb9 --- /dev/null +++ b/tests/auto/qml/qqmllistmodel/data/destroyObject.qml @@ -0,0 +1,23 @@ +import QtQml + +QtObject { + id: root + property ListModel projects: ListModel {} + property var object + + Component.onCompleted: { + var comp= Qt.createComponent("dummyItem.qml"); + object = comp.createObject(root, {}); + projects.append({"obj": object}); + } + + function destroy() { + try { + object.destroy(); + } catch(e) { + console.warn(e); + return false; + } + return true; + } +} diff --git a/tests/auto/qml/qqmllistmodel/data/dummyItem.qml b/tests/auto/qml/qqmllistmodel/data/dummyItem.qml new file mode 100644 index 0000000000..c9939efcdf --- /dev/null +++ b/tests/auto/qml/qqmllistmodel/data/dummyItem.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property var random: null +} diff --git a/tests/auto/qml/qqmllistmodel/data/objectOwnership.qml b/tests/auto/qml/qqmllistmodel/data/objectOwnership.qml new file mode 100644 index 0000000000..0ebb29d75b --- /dev/null +++ b/tests/auto/qml/qqmllistmodel/data/objectOwnership.qml @@ -0,0 +1,27 @@ +import QtQuick + +ListView { + id: root + width: 100 + height: 100 + + delegate: Component { + Item { + property Item myItem: refItem + } + } + + model: ListModel { + id: listModel + objectName: "listModel" + + function addItem() { + append({"refItem": cppOwnedItem}); + } + } + + function checkItem() { + root.currentIndex = 0; + currentItem.myItem.dummy(); + } +} diff --git a/tests/auto/qml/qqmllistmodel/data/protectQObjectFromGC.qml b/tests/auto/qml/qqmllistmodel/data/protectQObjectFromGC.qml new file mode 100644 index 0000000000..43b375b681 --- /dev/null +++ b/tests/auto/qml/qqmllistmodel/data/protectQObjectFromGC.qml @@ -0,0 +1,21 @@ +import QtQml +import QtQml.Models + +ListModel { + id: filesModel + property Component testComponent: Component { + id: testComponent + QtObject { + required property string name + } + } + Component.onCompleted: { + filesModel.clear() + for(let i = 0; i < 10; i++) { + filesModel.append({ + path: testComponent.createObject(null, { name: "" + i }) + }) + } + gc() + } +} diff --git a/tests/auto/qml/qqmllistmodel/data/urls.qml b/tests/auto/qml/qqmllistmodel/data/urls.qml index b7fe57402e..9e59a70cb6 100644 --- a/tests/auto/qml/qqmllistmodel/data/urls.qml +++ b/tests/auto/qml/qqmllistmodel/data/urls.qml @@ -4,16 +4,23 @@ import QtQml.Models 2 Item { id: root readonly property url url1: "http://qt-project.org" + property var result1 property var result2 + + property var alive1 + property var alive2 + ListModel {id: myModel} Component.onCompleted: { - myModel.append({"url": new URL("http://qt.io")}) - myModel.append({"url": url1}) + myModel.append({"url": new URL("http://qt.io"), "alive": "indeed"}) + myModel.append({"url": url1, "alive": "and kicking"}) const entry1 = myModel.get(0) root.result1 = entry1.url; + root.alive1 = entry1.alive; const entry2 = myModel.get(1) root.result2 = entry2.url; + root.alive2 = entry2.alive; } } diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index a9b6ec03a4..fbdf6d90f3 100644 --- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp +++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp @@ -39,7 +39,7 @@ #include <QtCore/qtranslator.h> #include <QSignalSpy> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> Q_DECLARE_METATYPE(QList<int>) Q_DECLARE_METATYPE(QList<QVariantHash>) @@ -74,6 +74,7 @@ class tst_qqmllistmodel : public QQmlDataTest Q_OBJECT public: tst_qqmllistmodel() + : QQmlDataTest(QT_QMLTEST_DATADIR) { qRegisterMetaType<QVector<int> >(); } @@ -136,6 +137,9 @@ private slots: void destroyObject(); void emptyStringNotUndefined(); void listElementWithTemplateString(); + void destroyComponentObject(); + void objectOwnershipFlip(); + void protectQObjectFromGC(); }; bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object) @@ -1406,6 +1410,8 @@ void tst_qqmllistmodel::url() QVERIFY(o); QCOMPARE(o->property("result1").toUrl(), QUrl("http://qt.io")); QCOMPARE(o->property("result2").toUrl(), QUrl("http://qt-project.org")); + QCOMPARE(o->property("alive1").toString(), QStringLiteral("indeed")); + QCOMPARE(o->property("alive2").toString(), QStringLiteral("and kicking")); } void tst_qqmllistmodel::datetime() @@ -1856,6 +1862,84 @@ void tst_qqmllistmodel::listElementWithTemplateString() QVERIFY(!root.isNull()); } +//QTBUG-95895 +void tst_qqmllistmodel::destroyComponentObject() +{ + QQmlEngine eng; + QQmlComponent component(&eng, testFileUrl("destroyObject.qml")); + QVERIFY(!component.isError()); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QQmlListModel *list = qvariant_cast<QQmlListModel *>(obj->property("projects")); + QVERIFY(list != nullptr); + QCOMPARE(list->count(), 1); + QPointer<QObject> created(qvariant_cast<QObject *>(obj->property("object"))); + QVERIFY(!created.isNull()); + QCOMPARE(list->get(0).property("obj").toQObject(), created.data()); + QVariant retVal; + QMetaObject::invokeMethod(obj.data(), + "destroy", + Qt::DirectConnection, + Q_RETURN_ARG(QVariant, retVal)); + QVERIFY(retVal.toBool()); + QTRY_VERIFY(created.isNull()); + QTRY_VERIFY(list->get(0).property("obj").isNull()); + QCOMPARE(list->count(), 1); +} + +// Used for objectOwnershipFlip +class TestItem : public QQuickItem +{ + Q_OBJECT +public: + // To trigger QQmlData::setImplicitDestructible through QV4::CallArgument::toValue + Q_INVOKABLE TestItem* dummy() { return this; } +}; + +void tst_qqmllistmodel::objectOwnershipFlip() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("objectOwnership.qml")); + QVERIFY(!component.isError()); + QScopedPointer<QObject> root(component.create()); + QVERIFY(!root.isNull()); + QQmlListModel *model = root->findChild<QQmlListModel*>("listModel"); + QVERIFY(model != nullptr); + + QScopedPointer<TestItem> item(new TestItem()); + item->setObjectName("cppOwnedItem"); + QJSEngine::setObjectOwnership(item.data(), QJSEngine::CppOwnership); + QCOMPARE(QJSEngine::objectOwnership(item.data()), QJSEngine::CppOwnership); + + engine.rootContext()->setContextProperty("cppOwnedItem", item.data()); + + QMetaObject::invokeMethod(model, "addItem"); + QCOMPARE(model->count(), 1); + + QMetaObject::invokeMethod(root.data(), "checkItem"); + + QCOMPARE(QJSEngine::objectOwnership(item.data()), QJSEngine::CppOwnership); +} + +void tst_qqmllistmodel::protectQObjectFromGC() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("protectQObjectFromGC.qml")); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + QScopedPointer<QObject> root(component.create()); + QVERIFY(!root.isNull()); + + QQmlListModel *listModel = qobject_cast<QQmlListModel *>(root.data()); + QVERIFY(listModel); + QCOMPARE(listModel->count(), 10); + + for (int i = 0; i < 10; ++i) { + QObject *element = qjsvalue_cast<QObject *>(listModel->get(i).property("path")); + QVERIFY(element); + QCOMPARE(element->property("name").toString(), QString::number(i)); + } +} + QTEST_MAIN(tst_qqmllistmodel) #include "tst_qqmllistmodel.moc" diff --git a/tests/auto/qml/qqmllistmodelworkerscript/CMakeLists.txt b/tests/auto/qml/qqmllistmodelworkerscript/CMakeLists.txt index 66c7c3a557..577ba74f9a 100644 --- a/tests/auto/qml/qqmllistmodelworkerscript/CMakeLists.txt +++ b/tests/auto/qml/qqmllistmodelworkerscript/CMakeLists.txt @@ -12,10 +12,7 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmllistmodelworkerscript SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmllistmodelworkerscript.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui @@ -23,6 +20,7 @@ qt_internal_add_test(tst_qqmllistmodelworkerscript Qt::QmlModelsPrivate Qt::QmlPrivate Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp index 262ac25d6a..93378ff647 100644 --- a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp +++ b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp @@ -38,7 +38,7 @@ #include <QtCore/qtranslator.h> #include <QSignalSpy> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> Q_DECLARE_METATYPE(QList<int>) Q_DECLARE_METATYPE(QList<QVariantHash>) @@ -73,6 +73,7 @@ class tst_qqmllistmodelworkerscript : public QQmlDataTest Q_OBJECT public: tst_qqmllistmodelworkerscript() + : QQmlDataTest(QT_QMLTEST_DATADIR) { qRegisterMetaType<QVector<int> >(); } diff --git a/tests/auto/qml/qqmllistreference/CMakeLists.txt b/tests/auto/qml/qqmllistreference/CMakeLists.txt index 15fa87b0b7..9d4b3cac7a 100644 --- a/tests/auto/qml/qqmllistreference/CMakeLists.txt +++ b/tests/auto/qml/qqmllistreference/CMakeLists.txt @@ -12,19 +12,21 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmllistreference SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmllistreference.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmllistreference) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp index 61565162e5..23b3847bc1 100644 --- a/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp +++ b/tests/auto/qml/qqmllistreference/tst_qqmllistreference.cpp @@ -37,13 +37,13 @@ #include <QtQml/qqmlproperty.h> #include <QDebug> #include <private/qquickstate_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmllistreference : public QQmlDataTest { Q_OBJECT public: - tst_qqmllistreference() {} + tst_qqmllistreference() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private: void modeData(); diff --git a/tests/auto/qml/qqmllocale/CMakeLists.txt b/tests/auto/qml/qqmllocale/CMakeLists.txt index 4022cb8cc4..ca7f464c37 100644 --- a/tests/auto/qml/qqmllocale/CMakeLists.txt +++ b/tests/auto/qml/qqmllocale/CMakeLists.txt @@ -12,14 +12,12 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmllocale SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmllocale.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::GuiPrivate Qt::Qml + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmllocale/data/functions.qml b/tests/auto/qml/qqmllocale/data/functions.qml index 9fee78a836..42e26a508c 100644 --- a/tests/auto/qml/qqmllocale/data/functions.qml +++ b/tests/auto/qml/qqmllocale/data/functions.qml @@ -3,9 +3,6 @@ import QtQuick QtObject { property var locale: Qt.locale() - // TODO: Workaround for not being able to use "Locale" in QQmlExpression (QTBUG-91747). - property var localeType: Locale - function setLocale(l) { locale = Qt.locale(l) } diff --git a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp index 3c9b1f1314..564c66c723 100644 --- a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp +++ b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp @@ -37,7 +37,7 @@ #include <QtCore/qscopedpointer.h> #include <QtCore/qtimezone.h> #include <qcolor.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <time.h> @@ -45,7 +45,7 @@ class tst_qqmllocale : public QQmlDataTest { Q_OBJECT public: - tst_qqmllocale() { } + tst_qqmllocale() : QQmlDataTest(QT_QMLTEST_DATADIR) { } private slots: void defaultLocale(); @@ -659,15 +659,15 @@ void tst_qqmllocale::addFormattedDataSizeDataForLocale(const QString &localeStr) expectedResult = locale.formattedDataSize(1000000, 3); QTest::newRow(qPrintable(makeTag())) << localeStr << functionCallScript << expectedResult << expectedErrorMessage; - functionCallScript = QLatin1String("locale.formattedDataSize(1000000, 3, localeType.DataSizeIecFormat)"); + functionCallScript = QLatin1String("locale.formattedDataSize(1000000, 3, Locale.DataSizeIecFormat)"); expectedResult = locale.formattedDataSize(1000000, 3, QLocale::DataSizeIecFormat); QTest::newRow(qPrintable(makeTag())) << localeStr << functionCallScript << expectedResult << expectedErrorMessage; - functionCallScript = QLatin1String("locale.formattedDataSize(1000000, 3, localeType.DataSizeTraditionalFormat)"); + functionCallScript = QLatin1String("locale.formattedDataSize(1000000, 3, Locale.DataSizeTraditionalFormat)"); expectedResult = locale.formattedDataSize(1000000, 3, QLocale::DataSizeTraditionalFormat); QTest::newRow(qPrintable(makeTag())) << localeStr << functionCallScript << expectedResult << expectedErrorMessage; - functionCallScript = QLatin1String("locale.formattedDataSize(1000000, 3, localeType.DataSizeSIFormat)"); + functionCallScript = QLatin1String("locale.formattedDataSize(1000000, 3, Locale.DataSizeSIFormat)"); expectedResult = locale.formattedDataSize(1000000, 3, QLocale::DataSizeSIFormat); QTest::newRow(qPrintable(makeTag())) << localeStr << functionCallScript << expectedResult << expectedErrorMessage; } @@ -691,7 +691,7 @@ void tst_qqmllocale::formattedDataSize_data() QString errorMessage = ".*Locale: formattedDataSize\\(\\): Expected 1-3 arguments, but received 0"; QTest::newRow("too few args") << "en_AU" << functionCallScript << QString() << errorMessage; - functionCallScript = "locale.formattedDataSize(10, 1, localeType.DataSizeIecFormat, \"foo\")"; + functionCallScript = "locale.formattedDataSize(10, 1, Locale.DataSizeIecFormat, \"foo\")"; errorMessage = ".*Locale: formattedDataSize\\(\\): Expected 1-3 arguments, but received 4"; QTest::newRow("too many args") << "en_AU" << functionCallScript << QString() << errorMessage; @@ -723,7 +723,9 @@ void tst_qqmllocale::formattedDataSize() QVERIFY(QMetaObject::invokeMethod(object.data(), "setLocale", Qt::DirectConnection, Q_ARG(QVariant, QVariant(localeStr)))); - QQmlExpression qmlExpression(engine.rootContext(), object.data(), functionCallScript); + // Make sure that we use the object's context rather than the root context, + // so that e.g. enums from the Locale type are available (QTBUG-91747). + QQmlExpression qmlExpression(qmlContext(object.data()), object.data(), functionCallScript); const QVariant evaluationResult = qmlExpression.evaluate(); if (expectedErrorMessagePattern.isEmpty()) { QVERIFY2(!qmlExpression.hasError(), qPrintable(qmlExpression.error().toString())); @@ -1437,7 +1439,7 @@ void tst_qqmllocale::timeZoneUpdated() obj.reset(c.create()); QVERIFY(obj); -#if !defined(Q_OS_LINUX) || defined(Q_OS_ANDROID) +#if (!defined(Q_OS_LINUX) && !defined(Q_OS_QNX)) || defined(Q_OS_ANDROID) QEXPECT_FAIL("", "Date.timeZoneUpdated() only works on non-Android Linux with QT_CONFIG(timezone).", Continue); @@ -1449,7 +1451,7 @@ void tst_qqmllocale::timeZoneUpdated() QMetaObject::invokeMethod(obj.data(), "check"); -#if !defined(Q_OS_LINUX) || defined(Q_OS_ANDROID) +#if (!defined(Q_OS_LINUX) && !defined(Q_OS_QNX)) || defined(Q_OS_ANDROID) QEXPECT_FAIL("", "Date.timeZoneUpdated() only works on non-Android Linux with QT_CONFIG(timezone).", Continue); diff --git a/tests/auto/qml/qqmlmetaobject/CMakeLists.txt b/tests/auto/qml/qqmlmetaobject/CMakeLists.txt index c7ec398a5d..93edb03527 100644 --- a/tests/auto/qml/qqmlmetaobject/CMakeLists.txt +++ b/tests/auto/qml/qqmlmetaobject/CMakeLists.txt @@ -12,17 +12,19 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlmetaobject SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlmetaobject.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::GuiPrivate Qt::Qml + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmlmetaobject) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp index af285fb58b..81c6b0d2a1 100644 --- a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp +++ b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp @@ -29,7 +29,7 @@ #include <QtTest/QtTest> #include <QtQml/qqmlcomponent.h> #include <QtQml/qqmlengine.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> Q_DECLARE_METATYPE(QMetaMethod::MethodType) @@ -42,6 +42,10 @@ QML_DECLARE_TYPE(MyQmlObject) class tst_QQmlMetaObject : public QQmlDataTest { Q_OBJECT + +public: + tst_QQmlMetaObject(); + private slots: void initTestCase() override; @@ -54,6 +58,11 @@ private: MyQmlObject myQmlObject; }; +tst_QQmlMetaObject::tst_QQmlMetaObject() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_QQmlMetaObject::initTestCase() { QQmlDataTest::initTestCase(); diff --git a/tests/auto/qml/qqmlmetatype/CMakeLists.txt b/tests/auto/qml/qqmlmetatype/CMakeLists.txt index 55eebaa651..74146bb49b 100644 --- a/tests/auto/qml/qqmlmetatype/CMakeLists.txt +++ b/tests/auto/qml/qqmlmetatype/CMakeLists.txt @@ -12,15 +12,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlmetatype SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlmetatype.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) @@ -48,6 +46,9 @@ qt_internal_add_resource(tst_qqmlmetatype "qmake_qmldirresource" ${qmake_qmldirresource_resource_files} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmlmetatype) +endif() ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp index 4d2e8c2b5d..f726855727 100644 --- a/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp +++ b/tests/auto/qml/qqmlmetatype/tst_qqmlmetatype.cpp @@ -37,13 +37,13 @@ #include <private/qqmlpropertyvalueinterceptor_p.h> #include <private/qqmlengine_p.h> #include <private/qqmlanybinding_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlmetatype : public QQmlDataTest { Q_OBJECT public: - tst_qqmlmetatype() {} + tst_qqmlmetatype() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; @@ -72,6 +72,8 @@ private slots: void enumsInRecursiveImport_data(); void enumsInRecursiveImport(); + + void clearPropertyCaches(); }; class TestType : public QObject @@ -734,6 +736,24 @@ void tst_qqmlmetatype::enumsInRecursiveImport() QTRY_COMPARE(obj->property("color").toString(), QString("green")); } +void tst_qqmlmetatype::clearPropertyCaches() +{ + qmlClearTypeRegistrations(); + qmlRegisterType<TestType>("ClearPropertyCaches", 1, 0, "A"); + + QQmlRefPointer<QQmlPropertyCache> oldCache( + QQmlMetaType::propertyCache(&TestType::staticMetaObject)); + QVERIFY(oldCache); + + qmlClearTypeRegistrations(); + qmlRegisterType<TestType>("ClearPropertyCaches", 1, 0, "B"); + QQmlRefPointer<QQmlPropertyCache> newCache( + QQmlMetaType::propertyCache(&TestType::staticMetaObject)); + QVERIFY(newCache); + + QVERIFY(oldCache.data() != newCache.data()); +} + QTEST_MAIN(tst_qqmlmetatype) #include "tst_qqmlmetatype.moc" diff --git a/tests/auto/qml/qqmlmoduleplugin/CMakeLists.txt b/tests/auto/qml/qqmlmoduleplugin/CMakeLists.txt index 18bd80b588..43b4c032df 100644 --- a/tests/auto/qml/qqmlmoduleplugin/CMakeLists.txt +++ b/tests/auto/qml/qqmlmoduleplugin/CMakeLists.txt @@ -20,17 +20,14 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlmoduleplugin SOURCES - ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h - ../../shared/util.cpp ../../shared/util.h tst_qqmlmoduleplugin.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::GuiPrivate Qt::Network Qt::QmlPrivate Qt::QuickShapesPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp index 4b58348962..8321e02d79 100644 --- a/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/protectedModule/plugin.cpp @@ -47,9 +47,9 @@ public: void registerTypes(const char *uri) override { - // The module is protected. The plugin can still be loaded, but it cannot register - // any types. + // Because the module is protected, this plugin should never be loaded Q_UNUSED(uri); + Q_UNREACHABLE(); } }; diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp index f1e6f7aa5a..dba70ac979 100644 --- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp @@ -46,8 +46,8 @@ #include <unistd.h> #endif -#include "../../shared/testhttpserver.h" -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/testhttpserver_p.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> // Note: this test does not use module identifier directives in the qmldir files, because // it would result in repeated attempts to insert types into the same namespace. @@ -58,6 +58,7 @@ class tst_qqmlmoduleplugin : public QQmlDataTest { Q_OBJECT public: + tst_qqmlmoduleplugin(); private slots: void initTestCase() override; @@ -175,6 +176,11 @@ void registerStaticPlugin(const char *uri) qRegisterStaticPluginFunction(plugin); }; +tst_qqmlmoduleplugin::tst_qqmlmoduleplugin() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_qqmlmoduleplugin::initTestCase() { QQmlDataTest::initTestCase(); diff --git a/tests/auto/qml/qqmlnotifier/CMakeLists.txt b/tests/auto/qml/qqmlnotifier/CMakeLists.txt index 5cc0495393..4056f06458 100644 --- a/tests/auto/qml/qqmlnotifier/CMakeLists.txt +++ b/tests/auto/qml/qqmlnotifier/CMakeLists.txt @@ -12,16 +12,18 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlnotifier SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlnotifier.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::Qml + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmlnotifier) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp index 836b94ad45..25eaa22b86 100644 --- a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp +++ b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp @@ -36,7 +36,7 @@ #include <QProcess> #endif -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class ExportedClass : public QObject { @@ -140,7 +140,7 @@ class tst_qqmlnotifier : public QQmlDataTest { Q_OBJECT public: - tst_qqmlnotifier() {} + tst_qqmlnotifier() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; diff --git a/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp b/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp index 6265c6ca67..27ecf24f26 100644 --- a/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp +++ b/tests/auto/qml/qqmlopenmetaobject/tst_qqmlopenmetaobject.cpp @@ -52,7 +52,9 @@ void tst_qqmlopenmetaobject::createProperties() { QQmlEngine engine; CustomObject object; - const QQmlRefPointer<QQmlOpenMetaObjectType> mot = new QQmlOpenMetaObjectType(object.metaObject()); + const QQmlRefPointer<QQmlOpenMetaObjectType> mot( + new QQmlOpenMetaObjectType(object.metaObject()), + QQmlRefPointer<QQmlOpenMetaObjectType>::Adopt); QQmlOpenMetaObject *const mo = new QQmlOpenMetaObject(&object, mot.data()); mo->setCached(true); mot->createProperty("customProperty"); diff --git a/tests/auto/qml/qqmlparser/CMakeLists.txt b/tests/auto/qml/qqmlparser/CMakeLists.txt index c322e29e94..004bb8ea31 100644 --- a/tests/auto/qml/qqmlparser/CMakeLists.txt +++ b/tests/auto/qml/qqmlparser/CMakeLists.txt @@ -12,16 +12,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlparser SOURCES - ../../shared/qqmljsastdumper.cpp ../../shared/qqmljsastdumper.h - ../../shared/util.cpp ../../shared/util.h tst_qqmlparser.cpp DEFINES SRCDIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}\\\" - INCLUDE_DIRECTORIES - ../../shared ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp index a480214219..1268ef8900 100644 --- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp +++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp @@ -32,8 +32,8 @@ #include <private/qqmljsastvisitor_p.h> #include <private/qqmljsast_p.h> -#include "../../shared/util.h" -#include "../../shared/qqmljsastdumper.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> +#include <QtQuickTestUtils/private/qqmljsastdumper_p.h> #include <qtest.h> #include <QDir> @@ -240,6 +240,7 @@ private: } tst_qqmlparser::tst_qqmlparser() + : QQmlDataTest(QT_QMLTEST_DATADIR) { } diff --git a/tests/auto/qml/qqmlpromise/CMakeLists.txt b/tests/auto/qml/qqmlpromise/CMakeLists.txt index e972ab08fb..ac0ffebabe 100644 --- a/tests/auto/qml/qqmlpromise/CMakeLists.txt +++ b/tests/auto/qml/qqmlpromise/CMakeLists.txt @@ -12,20 +12,22 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlpromise SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlpromise.cpp DEFINES QT_DISABLE_DEPRECATED_BEFORE=0 - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmlpromise) +endif() + #### Keys ignored in scope 1:.:.:qqmlpromise.pro:<TRUE>: # DISTFILES = "data/then-fulfilled-non-callable.qml" "data/then-reject-non-callable.qml" "data/then-resolve-multiple-then.qml" "data/then-resolve-chaining.qml" "data/then-reject-chaining.qml" "data/promise-resolve-with-value.qml" "data/promise-resolve-with-promise.qml" "data/promise-reject-with-value.qml" "data/promise-executor-resolve.qml" "data/promise-get-length.qml" "data/promise-executor-reject.qml" "data/promise-reject-catch.qml" "data/promise-async-resolve-with-value.qml" "data/promise-async-reject-with-value.qml" "data/promise-all-resolve.qml" "data/promise-all-empty-input.qml" "data/promise-resolve-with-array.qml" "data/promise-all-reject-reject-is-last.qml" "data/promise-all-reject-reject-is-mid.qml" "data/promise-race-resolve-1st.qml" "data/promise-race-empty-input.qml" "data/promise-race-resolve-2nd.qml" "data/promise-race-resolve-1st-in-executor-function.qml" "data/promise-resolve-is-a-function.qml" "data/promise-resolve-function-length.qml" "data/promise-all-invoke-then-method.qml" "data/promise-resolve-with-empty.qml" "data/promise-executor-throw-exception.qml" "data/promise-executor-function-extensible.qml" "data/promise-all-noniterable-input.qml" # OTHER_FILES = <EMPTY> diff --git a/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp b/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp index b430434526..2049376a86 100644 --- a/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp +++ b/tests/auto/qml/qqmlpromise/tst_qqmlpromise.cpp @@ -42,14 +42,14 @@ #include <QQmlComponent> #include <QDebug> #include <QScopedPointer> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlpromise : public QQmlDataTest { Q_OBJECT public: - tst_qqmlpromise() {} + tst_qqmlpromise() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void promise_all_empty_input(); diff --git a/tests/auto/qml/qqmlproperty/CMakeLists.txt b/tests/auto/qml/qqmlproperty/CMakeLists.txt index 2dabf0f948..1c695251f9 100644 --- a/tests/auto/qml/qqmlproperty/CMakeLists.txt +++ b/tests/auto/qml/qqmlproperty/CMakeLists.txt @@ -12,16 +12,14 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlproperty SOURCES - ../../shared/util.cpp ../../shared/util.h interfaces.h tst_qqmlproperty.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) @@ -47,4 +45,4 @@ set_target_properties(tst_qqmlproperty PROPERTIES QT_QML_MODULE_URI io.qt.bugreports ) -qt6_qml_type_registration(tst_qqmlproperty) +_qt_internal_qml_type_registration(tst_qqmlproperty) diff --git a/tests/auto/qml/qqmlproperty/data/bindToNonQObjectTarget.qml b/tests/auto/qml/qqmlproperty/data/bindToNonQObjectTarget.qml new file mode 100644 index 0000000000..d8a06aa5f9 --- /dev/null +++ b/tests/auto/qml/qqmlproperty/data/bindToNonQObjectTarget.qml @@ -0,0 +1,20 @@ +import QtQuick + +Item { + id: top; + visible:true; + width:300; + height:300 + Text { + id: text + width: 30; height: 30 + text: "1234.56" + font.bold: true + Binding { + target: text.font // which is not a QObject, so can't use it as a binding target + property: 'bold' + value: false; + when: width < 30 + } + } +} diff --git a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp index a1eae50048..7ea9b4183e 100644 --- a/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp +++ b/tests/auto/qml/qqmlproperty/tst_qqmlproperty.cpp @@ -40,8 +40,11 @@ #if QT_CONFIG(regularexpression) #include <QtCore/qregularexpression.h> #endif +#if QT_CONFIG(process) +#include <QtCore/qprocess.h> +#endif #include <QtCore/private/qobject_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include "qobject.h" #include <QtQml/QQmlPropertyMap> @@ -140,7 +143,7 @@ class tst_qqmlproperty : public QQmlDataTest { Q_OBJECT public: - tst_qqmlproperty() {} + tst_qqmlproperty() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; @@ -199,6 +202,10 @@ private slots: void signalExpressionWithoutObject(); void dontRemoveQPropertyBinding(); + void compatResolveUrls(); + + void bindToNonQObjectTarget(); + private: QQmlEngine engine; }; @@ -1995,7 +2002,8 @@ void tst_qqmlproperty::copy() { PropertyObject object; - QQmlProperty *property = new QQmlProperty(&object, QLatin1String("defaultProperty")); + QScopedPointer<QQmlProperty> property( + new QQmlProperty(&object, QLatin1String("defaultProperty"))); QCOMPARE(property->name(), QString("defaultProperty")); QCOMPARE(property->read(), QVariant(10)); QCOMPARE(property->type(), QQmlProperty::Property); @@ -2018,7 +2026,7 @@ void tst_qqmlproperty::copy() QCOMPARE(p2.propertyTypeCategory(), QQmlProperty::Normal); QCOMPARE(p2.propertyType(), QMetaType::Int); - delete property; property = nullptr; + property.reset(); QCOMPARE(p1.name(), QString("defaultProperty")); QCOMPARE(p1.read(), QVariant(10)); @@ -2031,6 +2039,16 @@ void tst_qqmlproperty::copy() QCOMPARE(p2.type(), QQmlProperty::Property); QCOMPARE(p2.propertyTypeCategory(), QQmlProperty::Normal); QCOMPARE(p2.propertyType(), QMetaType::Int); + + p1 = QQmlProperty(); + QQmlPropertyPrivate *p2d = QQmlPropertyPrivate::get(p2); + QCOMPARE(p2d->count(), 1); + + // Use a pointer to avoid compiler warning about self-assignment. + QQmlProperty *p2p = &p2; + *p2p = p2; + + QCOMPARE(p2d->count(), 1); } void tst_qqmlproperty::noContext() @@ -2300,6 +2318,64 @@ void tst_qqmlproperty::dontRemoveQPropertyBinding() QVERIFY(!object.bindableObjectName().hasBinding()); } +void tst_qqmlproperty::compatResolveUrls() +{ + QQmlEngine engine; + QQmlComponent c(&engine); + c.setData(R"( + import QtQml + QtObject { + property url a: "relative/url.png" + } + )", QUrl(QStringLiteral("qrc:/some/resource/path.qml"))); + QVERIFY(c.isReady()); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + + if (qEnvironmentVariableIsSet("QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT")) { + QCOMPARE(qvariant_cast<QUrl>(o->property("a")), + QUrl(QStringLiteral("qrc:/some/resource/relative/url.png"))); + return; + } + + QCOMPARE(qvariant_cast<QUrl>(o->property("a")), QUrl(QStringLiteral("relative/url.png"))); + +#ifdef Q_OS_ANDROID + QSKIP("Can't start QProcess to run a custom user binary on Android"); +#endif + +#if QT_CONFIG(process) + QProcess process; + process.setProgram(QCoreApplication::applicationFilePath()); + process.setEnvironment(QProcess::systemEnvironment() + + QStringList(u"QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT=1"_qs)); + process.setArguments({QStringLiteral("compatResolveUrls")}); + process.start(); + QVERIFY(process.waitForFinished()); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); + QCOMPARE(process.exitCode(), 0); +#else + QSKIP("Testing the QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT " + "environment variable requires QProcess."); +#endif +} + +void tst_qqmlproperty::bindToNonQObjectTarget() +{ + QQmlEngine engine; + const QUrl url = testFileUrl("bindToNonQObjectTarget.qml"); + QQmlComponent component(&engine, url); + + // Yes, we can still create the component. The result of the script expression will only be + // known once it's executed. + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + + QTest::ignoreMessage(QtWarningMsg, + qPrintable(url.toString() + ":14:7: Unable to assign QFont to QObject*")); + QScopedPointer<QObject> o(component.create()); + QVERIFY(!o.isNull()); +} + QTEST_MAIN(tst_qqmlproperty) #include "tst_qqmlproperty.moc" diff --git a/tests/auto/qml/qqmlpropertycache/CMakeLists.txt b/tests/auto/qml/qqmlpropertycache/CMakeLists.txt index 55f8c7b76b..cb396998bc 100644 --- a/tests/auto/qml/qqmlpropertycache/CMakeLists.txt +++ b/tests/auto/qml/qqmlpropertycache/CMakeLists.txt @@ -12,15 +12,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlpropertycache SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlpropertycache.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp index a3d84e3eb6..f8ca5e067e 100644 --- a/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp +++ b/tests/auto/qml/qqmlpropertycache/tst_qqmlpropertycache.cpp @@ -34,13 +34,13 @@ #include <private/qmetaobjectbuilder_p.h> #include <private/qqmlcontextdata_p.h> #include <QCryptographicHash> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlpropertycache : public QQmlDataTest { Q_OBJECT public: - tst_qqmlpropertycache() {} + tst_qqmlpropertycache() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void properties(); @@ -200,9 +200,8 @@ void tst_qqmlpropertycache::properties() DerivedObject object; const QMetaObject *metaObject = object.metaObject(); - QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(metaObject), - QQmlRefPointer<QQmlPropertyCache>::Adopt); - QQmlPropertyData *data; + QQmlRefPointer<QQmlPropertyCache> cache = QQmlPropertyCache::createStandalone(metaObject); + const QQmlPropertyData *data; QVERIFY((data = cacheProperty(cache, "propertyA"))); QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyA")); @@ -223,12 +222,12 @@ void tst_qqmlpropertycache::propertiesDerived() DerivedObject object; const QMetaObject *metaObject = object.metaObject(); - QQmlRefPointer<QQmlPropertyCache> parentCache( - new QQmlPropertyCache(&BaseObject::staticMetaObject), + QQmlRefPointer<QQmlPropertyCache> parentCache + = QQmlPropertyCache::createStandalone(&BaseObject::staticMetaObject); + QQmlRefPointer<QQmlPropertyCache> cache( + parentCache->copyAndAppend(object.metaObject(), QTypeRevision()), QQmlRefPointer<QQmlPropertyCache>::Adopt); - QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject(), QTypeRevision()), - QQmlRefPointer<QQmlPropertyCache>::Adopt); - QQmlPropertyData *data; + const QQmlPropertyData *data; QVERIFY((data = cacheProperty(cache, "propertyA"))); QCOMPARE(data->coreIndex(), metaObject->indexOfProperty("propertyA")); @@ -251,11 +250,10 @@ void tst_qqmlpropertycache::revisionedProperties() DerivedObject object; const QMetaObject *metaObject = object.metaObject(); - QQmlRefPointer<QQmlPropertyCache> cacheWithoutVersion(new QQmlPropertyCache(metaObject), - QQmlRefPointer<QQmlPropertyCache>::Adopt); - QQmlRefPointer<QQmlPropertyCache> cacheWithVersion( - new QQmlPropertyCache(metaObject, QTypeRevision::fromMinorVersion(1)), - QQmlRefPointer<QQmlPropertyCache>::Adopt); + QQmlRefPointer<QQmlPropertyCache> cacheWithoutVersion + = QQmlPropertyCache::createStandalone(metaObject); + QQmlRefPointer<QQmlPropertyCache> cacheWithVersion + = QQmlPropertyCache::createStandalone(metaObject, QTypeRevision::fromMinorVersion(1)); QQmlPropertyData *data; QVERIFY((data = cacheProperty(cacheWithoutVersion, "propertyE"))); @@ -269,9 +267,8 @@ void tst_qqmlpropertycache::methods() DerivedObject object; const QMetaObject *metaObject = object.metaObject(); - QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(metaObject), - QQmlRefPointer<QQmlPropertyCache>::Adopt); - QQmlPropertyData *data; + QQmlRefPointer<QQmlPropertyCache> cache(QQmlPropertyCache::createStandalone(metaObject)); + const QQmlPropertyData *data; QVERIFY((data = cacheProperty(cache, "slotA"))); QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("slotA()")); @@ -305,10 +302,10 @@ void tst_qqmlpropertycache::methodsDerived() const QMetaObject *metaObject = object.metaObject(); QQmlRefPointer<QQmlPropertyCache> parentCache( - new QQmlPropertyCache(&BaseObject::staticMetaObject), + QQmlPropertyCache::createStandalone(&BaseObject::staticMetaObject)); + QQmlRefPointer<QQmlPropertyCache> cache( + parentCache->copyAndAppend(object.metaObject(), QTypeRevision {}), QQmlRefPointer<QQmlPropertyCache>::Adopt); - QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject(), QTypeRevision {}), - QQmlRefPointer<QQmlPropertyCache>::Adopt); QQmlPropertyData *data; QVERIFY((data = cacheProperty(cache, "slotA"))); @@ -342,9 +339,8 @@ void tst_qqmlpropertycache::signalHandlers() DerivedObject object; const QMetaObject *metaObject = object.metaObject(); - QQmlRefPointer<QQmlPropertyCache> cache(new QQmlPropertyCache(metaObject), - QQmlRefPointer<QQmlPropertyCache>::Adopt); - QQmlPropertyData *data; + QQmlRefPointer<QQmlPropertyCache> cache(QQmlPropertyCache::createStandalone(metaObject)); + const QQmlPropertyData *data; QVERIFY((data = cacheProperty(cache, "onSignalA"))); QCOMPARE(data->coreIndex(), metaObject->indexOfMethod("signalA()")); @@ -372,10 +368,10 @@ void tst_qqmlpropertycache::signalHandlersDerived() const QMetaObject *metaObject = object.metaObject(); QQmlRefPointer<QQmlPropertyCache> parentCache( - new QQmlPropertyCache(&BaseObject::staticMetaObject), + QQmlPropertyCache::createStandalone(&BaseObject::staticMetaObject)); + QQmlRefPointer<QQmlPropertyCache> cache( + parentCache->copyAndAppend(object.metaObject(), QTypeRevision{}), QQmlRefPointer<QQmlPropertyCache>::Adopt); - QQmlRefPointer<QQmlPropertyCache> cache(parentCache->copyAndAppend(object.metaObject(), QTypeRevision{}), - QQmlRefPointer<QQmlPropertyCache>::Adopt); QQmlPropertyData *data; QVERIFY((data = cacheProperty(cache, "onSignalA"))); @@ -578,10 +574,28 @@ class TestClassWithClassInfo : public QObject #define ARRAY_SIZE(arr) \ int(sizeof(arr) / sizeof(arr[0])) +template <typename T, typename = void> +struct SizeofOffsetsAndSizes_helper +{ + static constexpr size_t value = sizeof(T::offsetsAndSize); // old moc +}; + +template <typename T> +struct SizeofOffsetsAndSizes_helper<T, std::void_t<decltype(T::offsetsAndSizes)>> +{ + static constexpr size_t value = sizeof(T::offsetsAndSizes); // new moc +}; + +template <typename T> +constexpr size_t sizeofOffsetsAndSizes(const T &) +{ + return SizeofOffsetsAndSizes_helper<T>::value; +} + #define TEST_CLASS(Class) \ QTest::newRow(#Class) \ << &Class::staticMetaObject << ARRAY_SIZE(qt_meta_data_##Class) \ - << int(sizeof(qt_meta_stringdata_##Class.offsetsAndSize) / (sizeof(uint) * 2)) + << int(sizeofOffsetsAndSizes(qt_meta_stringdata_##Class) / (sizeof(uint) * 2)) Q_DECLARE_METATYPE(const QMetaObject*); diff --git a/tests/auto/qml/qqmlpropertymap/CMakeLists.txt b/tests/auto/qml/qqmlpropertymap/CMakeLists.txt index 3092aa4eb2..291c221b23 100644 --- a/tests/auto/qml/qqmlpropertymap/CMakeLists.txt +++ b/tests/auto/qml/qqmlpropertymap/CMakeLists.txt @@ -12,16 +12,14 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlpropertymap SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlpropertymap.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlpropertymap/data/cached.qml b/tests/auto/qml/qqmlpropertymap/data/cached.qml new file mode 100644 index 0000000000..3222a672c3 --- /dev/null +++ b/tests/auto/qml/qqmlpropertymap/data/cached.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property string text: map ? map.c : "yada" +} diff --git a/tests/auto/qml/qqmlpropertymap/dummy_imports.qml b/tests/auto/qml/qqmlpropertymap/dummy_imports.qml index 4ae9d3f2cf..63d33cbea6 100644 --- a/tests/auto/qml/qqmlpropertymap/dummy_imports.qml +++ b/tests/auto/qml/qqmlpropertymap/dummy_imports.qml @@ -1,8 +1,7 @@ // This file exists for the sole purpose for qmlimportscanner to find // which modules it needs to extract for deployment. -// Otherwise, it fails to find the imports that are expressed in the -// C++ code belonging to the test. +// Otherwise, it fails to find the imports that are expressed in C++. -import QtQuick 2.0 +import QtQuick -QtObject { } // This is needed in order to keep importscanner happy +QtObject { } diff --git a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp index 07afc69a6d..a6eca4825a 100644 --- a/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp +++ b/tests/auto/qml/qqmlpropertymap/tst_qqmlpropertymap.cpp @@ -26,7 +26,7 @@ ** ****************************************************************************/ #include <qtest.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcontext.h> #include <QtQml/qqmlpropertymap.h> @@ -39,7 +39,7 @@ class tst_QQmlPropertyMap : public QQmlDataTest { Q_OBJECT public: - tst_QQmlPropertyMap() {} + tst_QQmlPropertyMap() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; @@ -64,6 +64,7 @@ private slots: void QTBUG_48136(); void lookupsInSubTypes(); void freeze(); + void cachedSignals(); }; class LazyPropertyMap : public QQmlPropertyMap, public QQmlParserStatus @@ -595,6 +596,46 @@ void tst_QQmlPropertyMap::freeze() QCOMPARE(map.value("key1").toString(), QStringLiteral("Hello World")); } +class Map: public QQmlPropertyMap +{ + Q_OBJECT +public: + Map(QObject *parent = nullptr) + : QQmlPropertyMap(this, parent) + { + insert( "a", u"yayayaya"_qs ); + insert( "b", u"yayayayb"_qs); + insert( "c", u"yayayayc"_qs); + insert( "d", u"yayayayd"_qs); + + freeze(); + } +}; + +void tst_QQmlPropertyMap::cachedSignals() +{ + Map foo; + QQmlEngine engine; + engine.rootContext()->setContextProperty("map", &foo); + const QUrl url = testFileUrl("cached.qml"); + QQmlComponent c(&engine, url); + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + QCOMPARE(o->property("text").toString(), u"yayayayc"_qs); + foo.setProperty("c", u"something"_qs); + QCOMPARE(o->property("text").toString(), u"something"_qs); + foo.insert("c", u"other"_qs); + QCOMPARE(o->property("text").toString(), u"other"_qs); + QTest::ignoreMessage( + QtWarningMsg, + qPrintable(url.toString() + u":4:5: Unable to assign [undefined] to QString"_qs)); + foo.clear("c"); + QCOMPARE(o->property("text").toString(), u"other"_qs); + foo.insert("c", u"final"_qs); + QCOMPARE(o->property("text").toString(), u"final"_qs); +} + QTEST_MAIN(tst_QQmlPropertyMap) #include "tst_qqmlpropertymap.moc" diff --git a/tests/auto/qml/qqmlqt/CMakeLists.txt b/tests/auto/qml/qqmlqt/CMakeLists.txt index 1c965d5c5a..863057372b 100644 --- a/tests/auto/qml/qqmlqt/CMakeLists.txt +++ b/tests/auto/qml/qqmlqt/CMakeLists.txt @@ -12,16 +12,14 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlqt SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlqt.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlqt/data/Other/A.qml b/tests/auto/qml/qqmlqt/data/Other/A.qml new file mode 100644 index 0000000000..7f0ce43d00 --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/Other/A.qml @@ -0,0 +1,8 @@ +import QtQml + +QtObject { + property QtObject there: QtObject {} + property url here: Qt.resolvedUrl(somewhere, there) + property url somewhere +} + diff --git a/tests/auto/qml/qqmlqt/data/Other/qmldir b/tests/auto/qml/qqmlqt/data/Other/qmldir new file mode 100644 index 0000000000..bee6252331 --- /dev/null +++ b/tests/auto/qml/qqmlqt/data/Other/qmldir @@ -0,0 +1,2 @@ +module Other +A 1.0 A.qml diff --git a/tests/auto/qml/qqmlqt/data/resolvedUrl.qml b/tests/auto/qml/qqmlqt/data/resolvedUrl.qml index aa57c73627..77c00c8618 100644 --- a/tests/auto/qml/qqmlqt/data/resolvedUrl.qml +++ b/tests/auto/qml/qqmlqt/data/resolvedUrl.qml @@ -1,6 +1,8 @@ import QtQuick 2.0 +import Other QtObject { + id: self property string result property bool isString: false property bool isObject: false @@ -11,5 +13,19 @@ QtObject { isString = (typeof a) == "string" isObject = (typeof a) == "object" } + + property A here: A { + there: self + somewhere: "somewhere.qml" + } + + property A there: A { + somewhere: "somewhere.qml" + } + + property url resolvedHere: here.here + property url resolvedThere: there.here + + property var unresolvedUrl: Qt.url("nowhere/else.js") } diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp index 62e42072b0..98308ddfa9 100644 --- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp +++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp @@ -44,14 +44,14 @@ #include <QQuaternion> #include <QMatrix4x4> #include <QFont> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <private/qglobal_p.h> class tst_qqmlqt : public QQmlDataTest { Q_OBJECT public: - tst_qqmlqt() {} + tst_qqmlqt() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; @@ -634,8 +634,9 @@ void tst_qqmlqt::openUrlExternally() { MyUrlHandler handler; + const QUrl htmlTestFile = testFileUrl("test.html"); QDesktopServices::setUrlHandler("test", &handler, "noteCall"); - QDesktopServices::setUrlHandler("file", &handler, "noteCall"); + QDesktopServices::setUrlHandler(htmlTestFile.scheme(), &handler, "noteCall"); QQmlComponent component(&engine, testFileUrl("openUrlExternally.qml")); QScopedPointer<QObject> object(component.create()); @@ -646,18 +647,19 @@ void tst_qqmlqt::openUrlExternally() object->setProperty("testFile", true); QCOMPARE(handler.called,2); - QCOMPARE(handler.last, testFileUrl("test.html")); + QCOMPARE(handler.last, htmlTestFile); QDesktopServices::unsetUrlHandler("test"); - QDesktopServices::unsetUrlHandler("file"); + QDesktopServices::unsetUrlHandler(htmlTestFile.scheme()); } void tst_qqmlqt::openUrlExternally_pragmaLibrary() { MyUrlHandler handler; + const QUrl htmlTestFile = testFileUrl("test.html"); QDesktopServices::setUrlHandler("test", &handler, "noteCall"); - QDesktopServices::setUrlHandler("file", &handler, "noteCall"); + QDesktopServices::setUrlHandler(htmlTestFile.scheme(), &handler, "noteCall"); QQmlComponent component(&engine, testFileUrl("openUrlExternally_lib.qml")); QScopedPointer<QObject> object(component.create()); @@ -668,10 +670,10 @@ void tst_qqmlqt::openUrlExternally_pragmaLibrary() object->setProperty("testFile", true); QCOMPARE(handler.called,2); - QCOMPARE(handler.last, testFileUrl("test.html")); + QCOMPARE(handler.last, htmlTestFile); QDesktopServices::unsetUrlHandler("test"); - QDesktopServices::unsetUrlHandler("file"); + QDesktopServices::unsetUrlHandler(htmlTestFile.scheme()); } void tst_qqmlqt::md5() @@ -1166,6 +1168,8 @@ void tst_qqmlqt::exit() void tst_qqmlqt::resolvedUrl() { + QQmlEngine engine; + engine.addImportPath(dataDirectory()); QQmlComponent component(&engine, testFileUrl("resolvedUrl.qml")); QScopedPointer<QObject> object(component.create()); @@ -1174,6 +1178,15 @@ void tst_qqmlqt::resolvedUrl() QCOMPARE(object->property("result").toString(), component.url().toString()); QCOMPARE(object->property("isString").toBool(), false); QCOMPARE(object->property("isObject").toBool(), true); + + QCOMPARE(qvariant_cast<QUrl>(object->property("resolvedHere")), + dataDirectoryUrl().resolved(QStringLiteral("somewhere.qml"))); + QCOMPARE(qvariant_cast<QUrl>(object->property("resolvedThere")), + dataDirectoryUrl().resolved(QStringLiteral("Other/somewhere.qml"))); + + QVariant unresolved = object->property("unresolvedUrl"); + QCOMPARE(unresolved.metaType(), QMetaType::fromType<QUrl>()); + QCOMPARE(qvariant_cast<QUrl>(unresolved), QUrl(QStringLiteral("nowhere/else.js"))); } void tst_qqmlqt::later_data() @@ -1354,7 +1367,7 @@ class TimeZoneSwitch { public: TimeZoneSwitch(const char *newZone) - : doChangeZone(qstrcmp(newZone, "localtime") == 0) + : doChangeZone(qstrcmp(newZone, "localtime") != 0) { if (!doChangeZone) return; @@ -1392,6 +1405,9 @@ void tst_qqmlqt::timeRoundtrip_data() // Local timezone: QTest::newRow("localtime") << QTime(0, 0, 0); +#if defined(Q_OS_WIN) || defined(Q_OS_ANDROID) || defined(Q_OS_MACOS) + qInfo("Omitting the tests that depend on setting local time's zone"); +#else // No DST: QTest::newRow("UTC") << QTime(0, 0, 0); QTest::newRow("Europe/Amsterdam") << QTime(1, 0, 0); @@ -1403,14 +1419,11 @@ void tst_qqmlqt::timeRoundtrip_data() QTest::newRow("Australia/Hobart") << QTime(10, 0, 0); QTest::newRow("Pacific/Auckland") << QTime(12, 0, 0); QTest::newRow("Pacific/Samoa") << QTime(13, 0, 0); +#endif } void tst_qqmlqt::timeRoundtrip() { -#ifdef Q_OS_WIN - QSKIP("On Windows, the DateObject doesn't handle DST transitions correctly when the timezone is not localtime."); // I.e.: for this test. -#endif - TimeZoneSwitch tzs(QTest::currentDataTag()); QFETCH(QTime, time); qmlRegisterTypesAndRevisions<TimeProvider>("Test", 1); diff --git a/tests/auto/qml/qqmlsettings/CMakeLists.txt b/tests/auto/qml/qqmlsettings/CMakeLists.txt index 01d35824da..5b5ba1e257 100644 --- a/tests/auto/qml/qqmlsettings/CMakeLists.txt +++ b/tests/auto/qml/qqmlsettings/CMakeLists.txt @@ -12,13 +12,11 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlsettings SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlsettings.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::Qml + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp b/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp index 60daeb0724..baaf126be3 100644 --- a/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp +++ b/tests/auto/qml/qqmlsettings/tst_qqmlsettings.cpp @@ -34,12 +34,15 @@ #include <QtGui/QFont> #include <QtQml/QQmlEngine> #include <QtQml/QQmlComponent> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_QQmlSettings : public QQmlDataTest { Q_OBJECT +public: + tst_QQmlSettings(); + private slots: void initTestCase() override; @@ -144,6 +147,11 @@ private: QFont m_fontProperty; }; +tst_QQmlSettings::tst_QQmlSettings() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_QQmlSettings::initTestCase() { QQmlDataTest::initTestCase(); diff --git a/tests/auto/qml/qqmlsqldatabase/CMakeLists.txt b/tests/auto/qml/qqmlsqldatabase/CMakeLists.txt index b9762b2eb6..aa40348e42 100644 --- a/tests/auto/qml/qqmlsqldatabase/CMakeLists.txt +++ b/tests/auto/qml/qqmlsqldatabase/CMakeLists.txt @@ -12,10 +12,7 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlsqldatabase SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlsqldatabase.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui @@ -23,6 +20,7 @@ qt_internal_add_test(tst_qqmlsqldatabase Qt::QmlPrivate Qt::QuickPrivate Qt::Sql + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml b/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml index 4ae9d3f2cf..63d33cbea6 100644 --- a/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml +++ b/tests/auto/qml/qqmlsqldatabase/dummy_imports.qml @@ -1,8 +1,7 @@ // This file exists for the sole purpose for qmlimportscanner to find // which modules it needs to extract for deployment. -// Otherwise, it fails to find the imports that are expressed in the -// C++ code belonging to the test. +// Otherwise, it fails to find the imports that are expressed in C++. -import QtQuick 2.0 +import QtQuick -QtObject { } // This is needed in order to keep importscanner happy +QtObject { } diff --git a/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp b/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp index 654877c7ea..b1516644a3 100644 --- a/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp +++ b/tests/auto/qml/qqmlsqldatabase/tst_qqmlsqldatabase.cpp @@ -34,13 +34,14 @@ #include <QtSql/qsqldatabase.h> #include <QtCore/qdir.h> #include <QtCore/qfile.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmlsqldatabase : public QQmlDataTest { Q_OBJECT public: tst_qqmlsqldatabase() + : QQmlDataTest(QT_QMLTEST_DATADIR) { qApp->setApplicationName("tst_qqmlsqldatabase"); qApp->setOrganizationName("QtProject"); diff --git a/tests/auto/qml/qqmltablemodel/CMakeLists.txt b/tests/auto/qml/qqmltablemodel/CMakeLists.txt index 75da1fc93f..02f93b5802 100644 --- a/tests/auto/qml/qqmltablemodel/CMakeLists.txt +++ b/tests/auto/qml/qqmltablemodel/CMakeLists.txt @@ -12,16 +12,14 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmltablemodel SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmltablemodel.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::Qml Qt::QmlPrivate Qt::Quick Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml b/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml index ebfe4ed930..fa5d5bf8bb 100644 --- a/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml +++ b/tests/auto/qml/qqmltablemodel/data/setDataThroughDelegate.qml @@ -65,21 +65,21 @@ Item { Connections { target: root enabled: column === 1 - onShouldModify: model.display = 18 + function onShouldModify() { model.display = 18 } } Connections { target: root enabled: column === 0 // Invalid: should be "display". - onShouldModifyInvalidRole: model.age = 100 + function onShouldModifyInvalidRole() { model.age = 100 } } Connections { target: root enabled: column === 1 // Invalid: should be string. - onShouldModifyInvalidType: model.display = "Whoops" + function onShouldModifyInvalidType() { model.display = "Whoops" } } } } diff --git a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp index 3923824fa2..a5db6bdd66 100644 --- a/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp +++ b/tests/auto/qml/qqmltablemodel/tst_qqmltablemodel.cpp @@ -36,14 +36,14 @@ #include <QtQuick/qquickview.h> #include <QtQuick/private/qquicktableview_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_QQmlTableModel : public QQmlDataTest { Q_OBJECT public: - tst_QQmlTableModel() {} + tst_QQmlTableModel() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void appendRemoveRow(); diff --git a/tests/auto/qml/qqmltimer/dummy_imports.qml b/tests/auto/qml/qqmltimer/dummy_imports.qml index f78e04d489..e189da6689 100644 --- a/tests/auto/qml/qqmltimer/dummy_imports.qml +++ b/tests/auto/qml/qqmltimer/dummy_imports.qml @@ -1,9 +1,8 @@ // This file exists for the sole purpose for qmlimportscanner to find // which modules it needs to extract for deployment. -// Otherwise, it fails to find the imports that are expressed in the -// C++ code belonging to the test. +// Otherwise, it fails to find the imports that are expressed in C++. -import QtQml 2.0 -import QtQuick 2.0 +import QtQml +import QtQuick -QtObject { } // This is needed in order to keep importscanner happy +QtObject { } diff --git a/tests/auto/qml/qqmltranslation/CMakeLists.txt b/tests/auto/qml/qqmltranslation/CMakeLists.txt index cb402b3e64..67047ff604 100644 --- a/tests/auto/qml/qqmltranslation/CMakeLists.txt +++ b/tests/auto/qml/qqmltranslation/CMakeLists.txt @@ -12,16 +12,15 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmltranslation SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmltranslation.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QmlModelsPrivate Qt::Quick + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) @@ -39,6 +38,13 @@ set_source_files_properties( ) # special case end +# On platforms where TESTDATA is embedded into resources (Android, iOS and +# INTEGRITY), the QT_RESOURCE_ALIAS property was previously set when processing +# TESTDATA, so we need to reset it. Otherwise the wrong alias will be written +# to introspect.qrc, and the related test will fail. +set_source_files_properties(${translation_resource_files} PROPERTIES + QT_RESOURCE_ALIAS "NOTFOUND") + qt_internal_add_resource(tst_qqmltranslation "translation" PREFIX "/" diff --git a/tests/auto/qml/qqmltranslation/data/translatedElements.qml b/tests/auto/qml/qqmltranslation/data/translatedElements.qml new file mode 100644 index 0000000000..c2edfe8c78 --- /dev/null +++ b/tests/auto/qml/qqmltranslation/data/translatedElements.qml @@ -0,0 +1,15 @@ +import QtQml +import QtQml.Models + +DelegateModel { + model: ListModel { + ListElement { dish: qsTr("soup"); price: 60 } + ListElement { dish: qsTr("fish"); price: 100 } + ListElement { dish: qsTr("meat"); price: 230 } + ListElement { dish: qsTr("bread"); price: 10 } + } + + delegate: QtObject { + required property string dish + } +} diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp index 73cdba5f8c..5e0046fb03 100644 --- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp +++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp @@ -34,13 +34,14 @@ #include <QQuickItem> #include <private/qqmlengine_p.h> #include <private/qqmltypedata_p.h> -#include "../../shared/util.h" +#include <private/qqmldelegatemodel_p.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qqmltranslation : public QQmlDataTest { Q_OBJECT public: - tst_qqmltranslation() {} + tst_qqmltranslation() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void translation_data(); @@ -48,6 +49,7 @@ private slots: void idTranslation(); void translationChange(); void preferJSContext(); + void listModel(); }; void tst_qqmltranslation::translation_data() @@ -97,13 +99,13 @@ void tst_qqmltranslation::translation() const bool expectCompiledTranslation = compiledTranslations.contains(propertyName); if (expectCompiledTranslation) { - if (binding->type != QV4::CompiledData::Binding::Type_Translation) + if (binding->type() != QV4::CompiledData::Binding::Type_Translation) qDebug() << "binding for property" << propertyName << "is not a compiled translation"; - QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_Translation)); + QCOMPARE(binding->type(), QV4::CompiledData::Binding::Type_Translation); } else { - if (binding->type == QV4::CompiledData::Binding::Type_Translation) + if (binding->type() == QV4::CompiledData::Binding::Type_Translation) qDebug() << "binding for property" << propertyName << "is not supposed to be a compiled translation"; - QVERIFY(binding->type != QV4::CompiledData::Binding::Type_Translation); + QVERIFY(binding->type() != QV4::CompiledData::Binding::Type_Translation); } } } @@ -149,11 +151,11 @@ void tst_qqmltranslation::idTranslation() for (quint32 i = 0; i < rootObject->nBindings; ++i, ++binding) { const QString propertyName = compilationUnit->stringAt(binding->propertyNameIndex); if (propertyName == "idTranslation") { - if (binding->type != QV4::CompiledData::Binding::Type_TranslationById) + if (binding->type() != QV4::CompiledData::Binding::Type_TranslationById) qDebug() << "binding for property" << propertyName << "is not a compiled translation"; - QCOMPARE(quint32(binding->type), quint32(QV4::CompiledData::Binding::Type_TranslationById)); + QCOMPARE(binding->type(), QV4::CompiledData::Binding::Type_TranslationById); } else { - QVERIFY(binding->type != QV4::CompiledData::Binding::Type_Translation); + QVERIFY(binding->type() != QV4::CompiledData::Binding::Type_Translation); } } } @@ -193,6 +195,14 @@ class DummyTranslator : public QTranslator return QString::fromUtf8("Deutsch in mylibrary"); if (!qstrcmp(sourceText, "English in translation") && !qstrcmp(context, "nested_js_translation")) return QString::fromUtf8("Deutsch in Setzung"); + if (!qstrcmp(sourceText, "soup")) + return QString::fromUtf8("Suppe"); + if (!qstrcmp(sourceText, "fish")) + return QString::fromUtf8("Fisch"); + if (!qstrcmp(sourceText, "meat")) + return QString::fromUtf8("Fleisch"); + if (!qstrcmp(sourceText, "bread")) + return QString::fromUtf8("Brot"); return QString(); } @@ -254,6 +264,35 @@ void tst_qqmltranslation::preferJSContext() QCoreApplication::removeTranslator(&translator); } +void tst_qqmltranslation::listModel() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("translatedElements.qml")); + QVERIFY2(component.isReady(), qPrintable(component.errorString())); + QScopedPointer<QObject> o(component.create()); + QVERIFY(o); + + QQmlDelegateModel *model = qobject_cast<QQmlDelegateModel *>(o.data()); + QVERIFY(model); + + QCOMPARE(model->count(), 4); + + QCOMPARE(model->object(0)->property("dish").toString(), QStringLiteral("soup")); + QCOMPARE(model->object(1)->property("dish").toString(), QStringLiteral("fish")); + QCOMPARE(model->object(2)->property("dish").toString(), QStringLiteral("meat")); + QCOMPARE(model->object(3)->property("dish").toString(), QStringLiteral("bread")); + + DummyTranslator translator; + QCoreApplication::installTranslator(&translator); + engine.setUiLanguage(QStringLiteral("xxx")); + engine.retranslate(); + + QCOMPARE(model->object(0)->property("dish").toString(), QStringLiteral("Suppe")); + QCOMPARE(model->object(1)->property("dish").toString(), QStringLiteral("Fisch")); + QCOMPARE(model->object(2)->property("dish").toString(), QStringLiteral("Fleisch")); + QCOMPARE(model->object(3)->property("dish").toString(), QStringLiteral("Brot")); +} + QTEST_MAIN(tst_qqmltranslation) #include "tst_qqmltranslation.moc" diff --git a/tests/auto/qml/qqmltypeloader/CMakeLists.txt b/tests/auto/qml/qqmltypeloader/CMakeLists.txt index b56dbd8944..e4f99ceaf3 100644 --- a/tests/auto/qml/qqmltypeloader/CMakeLists.txt +++ b/tests/auto/qml/qqmltypeloader/CMakeLists.txt @@ -12,16 +12,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmltypeloader SOURCES - ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h - ../../shared/util.cpp ../../shared/util.h declarativetesttype.h tst_qqmltypeloader.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Qml Qt::QmlPrivate Qt::Quick + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) @@ -56,5 +53,5 @@ set_target_properties(tst_qqmltypeloader PROPERTIES QT_QML_MODULE_URI declarative.import.for.typeloader.test ) -qt6_qml_type_registration(tst_qqmltypeloader) +_qt_internal_qml_type_registration(tst_qqmltypeloader) add_subdirectory(SlowImport) diff --git a/tests/auto/qml/qqmltypeloader/dummy_imports.qml b/tests/auto/qml/qqmltypeloader/dummy_imports.qml index a4684b2007..e189da6689 100644 --- a/tests/auto/qml/qqmltypeloader/dummy_imports.qml +++ b/tests/auto/qml/qqmltypeloader/dummy_imports.qml @@ -1,9 +1,8 @@ // This file exists for the sole purpose for qmlimportscanner to find // which modules it needs to extract for deployment. -// Otherwise, it fails to find the imports that are expressed in the -// C++ code belonging to the test. +// Otherwise, it fails to find the imports that are expressed in C++. -import QtQml 2.0 -import QtQuick 2.6 +import QtQml +import QtQuick -QtObject { } // This is needed in order to keep importscanner happy +QtObject { } diff --git a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp index c765a44637..9cbca71c28 100644 --- a/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp +++ b/tests/auto/qml/qqmltypeloader/tst_qqmltypeloader.cpp @@ -40,13 +40,16 @@ #include <QtQml/private/qqmltypeloader_p.h> #include <QtQml/private/qqmlirbuilder_p.h> #include <QtQml/private/qqmlirloader_p.h> -#include "../../shared/testhttpserver.h" -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/testhttpserver_p.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_QQMLTypeLoader : public QQmlDataTest { Q_OBJECT +public: + tst_QQMLTypeLoader(); + private slots: void testLoadComplete(); void loadComponentSynchronously(); @@ -73,6 +76,11 @@ private: void checkSingleton(const QString & dataDirectory); }; +tst_QQMLTypeLoader::tst_QQMLTypeLoader() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_QQMLTypeLoader::testLoadComplete() { #ifdef Q_OS_ANDROID @@ -562,6 +570,10 @@ void tst_QQMLTypeLoader::implicitComponentModule() void tst_QQMLTypeLoader::customDiskCachePath() { +#ifdef Q_OS_ANDROID + QSKIP("Android seems to have problems with QProcess"); +#endif + #if QT_CONFIG(process) const char *skipKey = "QT_TST_QQMLTYPELOADER_SKIP_MISMATCH"; if (qEnvironmentVariableIsSet(skipKey)) { @@ -725,6 +737,9 @@ void tst_QQMLTypeLoader::signalHandlersAreCompatible() // make sure that units really come from different places (the machinery // could in theory be smart enough to figure the qmlcachegen cached // version), fairly questionable check but better than nothing +#ifdef Q_OS_ANDROID + QSKIP("qrc and file system is the same thing on Android"); +#endif QVERIFY(unitFromCachegen->url() != unitFromTypeCompiler->url()); } diff --git a/tests/auto/qml/qqmlvaluetypeproviders/CMakeLists.txt b/tests/auto/qml/qqmlvaluetypeproviders/CMakeLists.txt index 697f501153..2ee105c48d 100644 --- a/tests/auto/qml/qqmlvaluetypeproviders/CMakeLists.txt +++ b/tests/auto/qml/qqmlvaluetypeproviders/CMakeLists.txt @@ -12,17 +12,15 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlvaluetypeproviders SOURCES - ../../shared/util.cpp ../../shared/util.h testtypes.cpp testtypes.h tst_qqmlvaluetypeproviders.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp index c0bc090bd9..6212c2d169 100644 --- a/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp +++ b/tests/auto/qml/qqmlvaluetypeproviders/tst_qqmlvaluetypeproviders.cpp @@ -34,7 +34,7 @@ #include <QScopedPointer> #include <private/qqmlglobal_p.h> #include <private/qquickvaluetypes_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include "testtypes.h" QT_BEGIN_NAMESPACE @@ -50,7 +50,7 @@ class tst_qqmlvaluetypeproviders : public QQmlDataTest { Q_OBJECT public: - tst_qqmlvaluetypeproviders() {} + tst_qqmlvaluetypeproviders() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; diff --git a/tests/auto/qml/qqmlvaluetypes/CMakeLists.txt b/tests/auto/qml/qqmlvaluetypes/CMakeLists.txt index fc76a3ff12..25bf4a4c9e 100644 --- a/tests/auto/qml/qqmlvaluetypes/CMakeLists.txt +++ b/tests/auto/qml/qqmlvaluetypes/CMakeLists.txt @@ -12,17 +12,15 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlvaluetypes SOURCES - ../../shared/util.cpp ../../shared/util.h testtypes.cpp testtypes.h tst_qqmlvaluetypes.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate Qt::QuickPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp index c062b9cd56..d4524fb421 100644 --- a/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp +++ b/tests/auto/qml/qqmlvaluetypes/tst_qqmlvaluetypes.cpp @@ -36,7 +36,7 @@ #include <private/qqmlglobal_p.h> #include <private/qv4engine_p.h> #include <private/qv4variantobject_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include "testtypes.h" QT_BEGIN_NAMESPACE @@ -47,7 +47,7 @@ class tst_qqmlvaluetypes : public QQmlDataTest { Q_OBJECT public: - tst_qqmlvaluetypes() {} + tst_qqmlvaluetypes() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; @@ -102,6 +102,7 @@ private slots: void char16Type(); void writeBackOnFunctionCall(); void valueTypeConversions(); + void readReferenceOnGetOwnProperty(); private: QQmlEngine engine; @@ -1976,6 +1977,35 @@ void tst_qqmlvaluetypes::valueTypeConversions() QCOMPARE(resultB.b, a.a); } +class Chose : public QObject +{ + Q_OBJECT + Q_PROPERTY(QRectF f READ ff CONSTANT) +public: + Chose(QObject *parent = nullptr) : QObject(parent) {} + QRectF ff() const { return QRectF(); } + Q_INVOKABLE bool g(QJSValue v) { return v.hasProperty("x"); } +}; + +void tst_qqmlvaluetypes::readReferenceOnGetOwnProperty() +{ + Chose chose; + QQmlEngine engine; + engine.rootContext()->setContextProperty(QStringLiteral("chose"), &chose); + QQmlComponent c(&engine); + c.setData(R"fin( + import QtQml + QtObject { + property bool allo: chose.g(chose.f) + } + )fin", QUrl()); + + QVERIFY2(c.isReady(), qPrintable(c.errorString())); + QScopedPointer<QObject> o(c.create()); + QVERIFY(!o.isNull()); + QVERIFY(o->property("allo").toBool()); +} + #undef CHECK_TYPE_IS_NOT_VALUETYPE QTEST_MAIN(tst_qqmlvaluetypes) diff --git a/tests/auto/qml/qqmlxmlhttprequest/CMakeLists.txt b/tests/auto/qml/qqmlxmlhttprequest/CMakeLists.txt index 4f428fe3a1..ea244fcbe4 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/CMakeLists.txt +++ b/tests/auto/qml/qqmlxmlhttprequest/CMakeLists.txt @@ -12,20 +12,21 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlxmlhttprequest SOURCES - ../../shared/testhttpserver.cpp ../../shared/testhttpserver.h - ../../shared/util.cpp ../../shared/util.h tst_qqmlxmlhttprequest.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::Network Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qqmlxmlhttprequest) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/WebDAV/propfind.collection.allprop.expect b/tests/auto/qml/qqmlxmlhttprequest/data/WebDAV/propfind.collection.allprop.expect index 69330e441a..6dba52d2de 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/WebDAV/propfind.collection.allprop.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/WebDAV/propfind.collection.allprop.expect @@ -2,7 +2,6 @@ PROPFIND /container/ HTTP/1.1 Depth: 1 Content-Length: 95 Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} Accept-Language: en-US,* diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/WebDAV/propfind.file.expect b/tests/auto/qml/qqmlxmlhttprequest/data/WebDAV/propfind.file.expect index d752cf203a..dc7217d45c 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/WebDAV/propfind.file.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/WebDAV/propfind.file.expect @@ -1,7 +1,6 @@ PROPFIND /file HTTP/1.1 Content-Length: 192 -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} Accept-Language: en-US,* diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/abort.expect b/tests/auto/qml/qqmlxmlhttprequest/data/abort.expect index d317f51b73..97c1661851 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/abort.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/abort.expect @@ -2,8 +2,7 @@ PUT /testdocument.html HTTP/1.1 Accept-Language: en-US Content-Type: text/plain;charset=UTF-8 Content-Length: 10 -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/getResponseHeader.expect b/tests/auto/qml/qqmlxmlhttprequest/data/getResponseHeader.expect index dbc37463f5..2270e7f3aa 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/getResponseHeader.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/getResponseHeader.expect @@ -1,7 +1,6 @@ GET /testdocument.html HTTP/1.1 Accept-Language: en-US -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/open_network.expect b/tests/auto/qml/qqmlxmlhttprequest/data/open_network.expect index dbc37463f5..2270e7f3aa 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/open_network.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/open_network.expect @@ -1,7 +1,6 @@ GET /testdocument.html HTTP/1.1 Accept-Language: en-US -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/receive_binary_data.expect b/tests/auto/qml/qqmlxmlhttprequest/data/receive_binary_data.expect index e56c2eec41..35d28ec76d 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/receive_binary_data.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/receive_binary_data.expect @@ -1,8 +1,7 @@ GET /gml_logo.png HTTP/1.1 Accept-Language: en-US,* Content-Type: image/png -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/receive_json_data.expect b/tests/auto/qml/qqmlxmlhttprequest/data/receive_json_data.expect index 38a9ffd705..9784ba4a80 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/receive_json_data.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/receive_json_data.expect @@ -1,8 +1,7 @@ GET /json.data HTTP/1.1 Accept-Language: en-US,* Content-Type: application/jsonrequest -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.1.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.1.expect index e24608d7c3..64bd2b3818 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.1.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.1.expect @@ -2,8 +2,7 @@ POST /testdocument.html HTTP/1.1 Accept-Language: en-US Content-Type: text/plain;charset=UTF-8 Content-Length: 13 -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.10.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.10.expect index 29828c06d0..2bf3b5a081 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.10.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.10.expect @@ -2,8 +2,7 @@ OPTIONS /testdocument.html HTTP/1.1 Accept-Language: en-US,* Content-Type: text/plain;charset=UTF-8 Content-Length: 13 -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.expect Binary files differindex e3a9aae9e2..7132819c72 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.expect diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.4.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.4.expect index 02f48d0abb..270ee838d9 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.4.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.4.expect @@ -2,8 +2,7 @@ POST /testdocument.html HTTP/1.1 Accept-Language: en-US Content-Type: charset=UTF-8;text/plain Content-Length: 13 -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.6.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.6.expect index 2b60a6db86..f6c8083875 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.6.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.6.expect @@ -2,8 +2,7 @@ PUT /testdocument.html HTTP/1.1 Accept-Language: en-US Content-Type: text/plain;charset=UTF-8 Content-Length: 13 -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.8.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.8.expect index f3db27c891..bcd7e79fc1 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.8.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.8.expect @@ -1,7 +1,6 @@ OPTIONS / HTTP/1.1 Content-Length: 0 -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} Accept-Language: en-US,* diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.9.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.9.expect index 347181efae..2d4f2c3146 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.9.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.9.expect @@ -1,7 +1,6 @@ OPTIONS /testdocument.html HTTP/1.1 Content-Length: 0 -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} Accept-Language: en-US,* diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_DELETE.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_DELETE.expect index 0f13fc0bf9..7d96c00101 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_DELETE.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_DELETE.expect @@ -1,7 +1,6 @@ DELETE /testdocument.html HTTP/1.1 Accept-Language: en-US -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_GET.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_GET.expect index dbc37463f5..2270e7f3aa 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_GET.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_GET.expect @@ -1,7 +1,6 @@ GET /testdocument.html HTTP/1.1 Accept-Language: en-US -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_HEAD.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_HEAD.expect index 9d2d6bc475..064cf1b6b7 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_HEAD.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_ignoreData_HEAD.expect @@ -1,7 +1,6 @@ HEAD /testdocument.html HTTP/1.1 Accept-Language: en-US -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect index 3ff8a42028..55f7f7dceb 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_patch.expect @@ -3,8 +3,7 @@ Accept-Language: en-US If-Match: "ETagNumber" Content-Type: application/example Content-Length: 247 -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/setRequestHeader.expect b/tests/auto/qml/qqmlxmlhttprequest/data/setRequestHeader.expect index a676062ec0..003e54f33c 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/setRequestHeader.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/setRequestHeader.expect @@ -2,8 +2,7 @@ GET /testdocument.html HTTP/1.1 Accept-Language: en-US Test-header: value Test-header2: value,value2 -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/status.expect b/tests/auto/qml/qqmlxmlhttprequest/data/status.expect index dbc37463f5..2270e7f3aa 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/data/status.expect +++ b/tests/auto/qml/qqmlxmlhttprequest/data/status.expect @@ -1,7 +1,6 @@ GET /testdocument.html HTTP/1.1 Accept-Language: en-US -Connection: Keep-Alive, Upgrade, HTTP2-Settings -Upgrade: h2c +Connection: Keep-Alive{{Ignore}} HTTP2-Settings: {{Ignore}} Accept-Encoding: {{Ignore}} User-Agent: Mozilla/5.0 diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp index 401152d575..d1dcf3829a 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp +++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp @@ -42,14 +42,14 @@ #include <QProcessEnvironment> #endif -#include "testhttpserver.h" -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> +#include <QtQuickTestUtils/private/testhttpserver_p.h> class tst_qqmlxmlhttprequest : public QQmlDataTest { Q_OBJECT public: - tst_qqmlxmlhttprequest() {} + tst_qqmlxmlhttprequest() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override; @@ -662,6 +662,8 @@ void tst_qqmlxmlhttprequest::send_options() void tst_qqmlxmlhttprequest::send_options_data() { + if (QLocale::system() != QLocale(QLocale::English, QLocale::UnitedStates)) + QSKIP("Test is locale dependent"); QTest::addColumn<QString>("url_suffix"); QTest::addColumn<QString>("file_expected"); QTest::addColumn<QString>("file_qml"); @@ -886,6 +888,8 @@ void tst_qqmlxmlhttprequest::getAllResponseHeaders_args() void tst_qqmlxmlhttprequest::getBinaryData() { + if (QLocale::system() != QLocale(QLocale::English, QLocale::UnitedStates)) + QSKIP("Test is locale dependent"); TestHTTPServer server; QVERIFY2(server.listen(), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("receive_binary_data.expect"), @@ -905,6 +909,8 @@ void tst_qqmlxmlhttprequest::getBinaryData() void tst_qqmlxmlhttprequest::getJsonData() { + if (QLocale::system() != QLocale(QLocale::English, QLocale::UnitedStates)) + QSKIP("Test is locale dependent"); TestHTTPServer server; QVERIFY2(server.listen(), qPrintable(server.errorString())); QVERIFY(server.wait(testFileUrl("receive_json_data.expect"), @@ -1087,6 +1093,10 @@ static const QString testString = QStringLiteral("Test-String"); void tst_qqmlxmlhttprequest::doFileRequest(std::function<void(QObject *component, QTemporaryFile &writeFile)> verifyFunction) { +#if defined(Q_OS_INTEGRITY) + QSKIP("There's no mounted filesystem on INTEGRITY."); +#endif + // Create test files QTemporaryFile writeFile; QTemporaryFile readFile; @@ -1131,6 +1141,9 @@ void tst_qqmlxmlhttprequest::sendFileRequest() #if QT_CONFIG(process) void tst_qqmlxmlhttprequest::sendFileRequestNotSet() { +#ifdef Q_OS_ANDROID + QSKIP("Trying to run the main app .so lib crashes on Android (QTBUG-99214)"); +#endif if (qEnvironmentVariableIsSet("TEST_CUSTOM_PERMISSIONS")) { // Test with no settings, neither reading nor writing should work doFileRequest([](QObject *object, QTemporaryFile &writeFile) { @@ -1185,6 +1198,10 @@ void tst_qqmlxmlhttprequest::sendFileRequestNotSet() { #if QT_CONFIG(process) void tst_qqmlxmlhttprequest::sendFileRequestNoWrite() { +#ifdef Q_OS_ANDROID + QSKIP("Trying to run the main app .so lib crashes on Android (QTBUG-99214)"); +#endif + if (qEnvironmentVariableIsSet("TEST_CUSTOM_PERMISSIONS")) { // Test with no writing enabled doFileRequest([](QObject* object, QTemporaryFile &writeFile) { @@ -1214,6 +1231,10 @@ void tst_qqmlxmlhttprequest::sendFileRequestNoWrite() { #if QT_CONFIG(process) void tst_qqmlxmlhttprequest::sendFileRequestNoRead() { +#ifdef Q_OS_ANDROID + QSKIP("Trying to run the main app .so lib crashes on Android (QTBUG-99214)"); +#endif + if (qEnvironmentVariableIsSet("TEST_CUSTOM_PERMISSIONS")) { // Test with no reading enabled doFileRequest([](QObject* object, QTemporaryFile &writeFile) { @@ -1246,6 +1267,8 @@ void tst_qqmlxmlhttprequest::sendFileRequestNoRead() { void tst_qqmlxmlhttprequest::sendPropfind() { + if (QLocale::system() != QLocale(QLocale::English, QLocale::UnitedStates)) + QSKIP("Test is locale dependent"); const QString prefix = "WebDAV//"; QFETCH(QString, qml); diff --git a/tests/auto/qml/qqmlxmllistmodel/CMakeLists.txt b/tests/auto/qml/qqmlxmllistmodel/CMakeLists.txt index 3748661ce2..b529ceed8e 100644 --- a/tests/auto/qml/qqmlxmllistmodel/CMakeLists.txt +++ b/tests/auto/qml/qqmlxmllistmodel/CMakeLists.txt @@ -5,14 +5,12 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qqmlxmllistmodel SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qqmlxmllistmodel.cpp - INCLUDE_DIRECTORIES - ../../shared LIBRARIES Qt::Core Qt::Qml Qt::QmlXmlListModelPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qqmlxmllistmodel/tst_qqmlxmllistmodel.cpp b/tests/auto/qml/qqmlxmllistmodel/tst_qqmlxmllistmodel.cpp index 804a10ba72..66878e41d1 100644 --- a/tests/auto/qml/qqmlxmllistmodel/tst_qqmlxmllistmodel.cpp +++ b/tests/auto/qml/qqmlxmllistmodel/tst_qqmlxmllistmodel.cpp @@ -36,7 +36,7 @@ #include <QNetworkRequest> #include <QNetworkAccessManager> #include <QtQmlXmlListModel/private/qqmlxmllistmodel_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> typedef QList<QVariantList> QQmlXmlModelData; @@ -48,7 +48,7 @@ class tst_QQmlXmlListModel : public QQmlDataTest { Q_OBJECT public: - tst_QQmlXmlListModel() { } + tst_QQmlXmlListModel() : QQmlDataTest(QT_QMLTEST_DATADIR) { } private slots: void initTestCase() override @@ -132,9 +132,9 @@ private: class ScopedFile { public: - ScopedFile(const QUrl &url, const QByteArray &data) : m_fileUrl(url) + ScopedFile(const QString &fileName, const QByteArray &data) : m_fileName(fileName) { - m_file.setFileName(url.toLocalFile()); + m_file.setFileName(fileName); m_created = m_file.open(QIODevice::WriteOnly | QIODevice::Truncate); if (m_created) { const auto written = m_file.write(data); @@ -145,11 +145,11 @@ public: ~ScopedFile() { QFile::remove(m_file.fileName()); } bool isCreated() const { return m_created; } - QUrl fileUrl() const { return m_fileUrl; } + QString fileName() const { return m_fileName; } private: QFile m_file; - const QUrl m_fileUrl; + const QString m_fileName; bool m_created = false; }; @@ -380,7 +380,9 @@ void tst_QQmlXmlListModel::source() if (model->property("source").toString().isEmpty()) QCOMPARE(qvariant_cast<QQmlXmlListModel::Status>(model->property("status")), QQmlXmlListModel::Null); - QCOMPARE(model->property("progress").toDouble(), qreal(source.isLocalFile() ? 1.0 : 0.0)); + qreal expectedProgress = + (source.isLocalFile() || (source.scheme() == QLatin1String("qrc"))) ? 1.0 : 0.0; + QCOMPARE(model->property("progress").toDouble(), expectedProgress); QTRY_COMPARE(spy.count(), 1); spy.clear(); QCOMPARE(qvariant_cast<QQmlXmlListModel::Status>(model->property("status")), @@ -488,6 +490,8 @@ void tst_QQmlXmlListModel::threading() QScopedPointer<QAbstractItemModel> m3(qobject_cast<QAbstractItemModel *>(component.create())); QVERIFY(m3 != nullptr); + QTemporaryDir tempDir; + for (int dataCount = 0; dataCount < xmlDataCount; ++dataCount) { QString data1, data2, data3; for (int i = 0; i < dataCount; ++i) { @@ -499,14 +503,14 @@ void tst_QQmlXmlListModel::threading() + ",sport=Curling;"; } - ScopedFile f1(testFileUrl("file1.xml"), makeItemXmlAndData(data1).toLatin1()); - ScopedFile f2(testFileUrl("file2.xml"), makeItemXmlAndData(data2).toLatin1()); - ScopedFile f3(testFileUrl("file3.xml"), makeItemXmlAndData(data3).toLatin1()); + ScopedFile f1(tempDir.filePath("file1.xml"), makeItemXmlAndData(data1).toLatin1()); + ScopedFile f2(tempDir.filePath("file2.xml"), makeItemXmlAndData(data2).toLatin1()); + ScopedFile f3(tempDir.filePath("file3.xml"), makeItemXmlAndData(data3).toLatin1()); QVERIFY(f1.isCreated() && f2.isCreated() && f3.isCreated()); - m1->setProperty("source", f1.fileUrl()); - m2->setProperty("source", f2.fileUrl()); - m3->setProperty("source", f3.fileUrl()); + m1->setProperty("source", QUrl::fromLocalFile(f1.fileName())); + m2->setProperty("source", QUrl::fromLocalFile(f2.fileName())); + m3->setProperty("source", QUrl::fromLocalFile(f3.fileName())); QCoreApplication::processEvents(); QTRY_VERIFY(m1->rowCount() == dataCount && m2->rowCount() == dataCount diff --git a/tests/auto/qml/qquickfolderlistmodel/CMakeLists.txt b/tests/auto/qml/qquickfolderlistmodel/CMakeLists.txt index 58aa6e95f1..f6752765b4 100644 --- a/tests/auto/qml/qquickfolderlistmodel/CMakeLists.txt +++ b/tests/auto/qml/qquickfolderlistmodel/CMakeLists.txt @@ -12,15 +12,13 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qquickfolderlistmodel SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qquickfolderlistmodel.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) @@ -29,6 +27,13 @@ set(introspect_resource_files "data/txtdir/hello.txt" ) +# On platforms where TESTDATA is embedded into resources (Android, iOS and +# INTEGRITY), the QT_RESOURCE_ALIAS property was previously set when processing +# TESTDATA, so we need to reset it. Otherwise the wrong alias will be written +# to introspect.qrc, and the related test will fail. +set_source_files_properties(${introspect_resource_files} PROPERTIES + QT_RESOURCE_ALIAS "NOTFOUND") + qt_internal_add_resource(tst_qquickfolderlistmodel "introspect" PREFIX "/myprefix/subdir" diff --git a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp index d49e9b952b..cc35510762 100644 --- a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp +++ b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp @@ -33,7 +33,7 @@ #include <QtCore/qfile.h> #include <QtCore/qabstractitemmodel.h> #include <QDebug> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #if defined (Q_OS_WIN) #include <qt_windows.h> @@ -48,7 +48,7 @@ class tst_qquickfolderlistmodel : public QQmlDataTest { Q_OBJECT public: - tst_qquickfolderlistmodel() {} + tst_qquickfolderlistmodel() : QQmlDataTest(QT_QMLTEST_DATADIR) {} public slots: void removed(const QModelIndex &, int start, int end) { @@ -85,6 +85,10 @@ private: void tst_qquickfolderlistmodel::initTestCase() { +#if defined(Q_OS_MACOS) && defined(Q_PROCESSOR_ARM_64) + // ### TODO: this is only a temporary workaround for QTBUG-99665 + QSKIP("Test crashes after running to completion on macos ARM"); +#endif // The tests rely on a fixed number of files in the directory with the qml files // (the data dir), so disable the disk cache to avoid creating .qmlc files and // confusing the test. @@ -94,28 +98,27 @@ void tst_qquickfolderlistmodel::initTestCase() void tst_qquickfolderlistmodel::basicProperties() { -#ifdef Q_OS_ANDROID - QSKIP("[QTBUG-77335] Initial folder of FolderListModel on Android does not work properly," - " and from there on it is unreliable to change the folder"); -#endif QQmlComponent component(&engine, testFileUrl("basic.qml")); QTRY_VERIFY2(component.isReady(), qPrintable(component.errorString())); QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create()); QVERIFY(flm != nullptr); + QSignalSpy folderChangedSpy(flm, SIGNAL(folderChanged())); QCOMPARE(flm->property("nameFilters").toStringList(), QStringList() << "*.qml"); // from basic.qml QCOMPARE(flm->property("folder").toUrl(), QUrl::fromLocalFile(QDir::currentPath())); + folderChangedSpy.wait(); // wait for the initial folder to be processed - // wait for the initial directory listing (it will find at least the "data" dir, - // and other dirs on Windows). - QTRY_VERIFY(flm->property("count").toInt() > 0); - - QSignalSpy folderChangedSpy(flm, SIGNAL(folderChanged())); flm->setProperty("folder", dataDirectoryUrl()); QVERIFY(folderChangedSpy.wait()); QCOMPARE(flm->property("count").toInt(), 9); QCOMPARE(flm->property("folder").toUrl(), dataDirectoryUrl()); - QCOMPARE(flm->property("parentFolder").toUrl(), QUrl::fromLocalFile(QDir(directory()).canonicalPath())); +#ifndef Q_OS_ANDROID + // On Android currentDir points to some dir in qrc://, which is not + // considered to be local file, so parentFolder is always + // default-constructed QUrl. + QCOMPARE(flm->property("parentFolder").toUrl(), + QUrl::fromLocalFile(QDir(directory()).canonicalPath())); +#endif QCOMPARE(flm->property("sortField").toInt(), int(Name)); QCOMPARE(flm->property("nameFilters").toStringList(), QStringList() << "*.qml"); QCOMPARE(flm->property("sortReversed").toBool(), false); @@ -195,6 +198,14 @@ void tst_qquickfolderlistmodel::nameFilters() connect(flm, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(removed(QModelIndex,int,int))); +#ifdef Q_OS_ANDROID + // On Android the default folder is application's "files" dir, which + // requires special rights for reading. The test works when started via + // androidtestrunner, but fails when launching the APK directly. Set the + // initial folder to resources root dir, because it is always readable. + flm->setProperty("folder", testFileUrl("")); +#endif + QTRY_VERIFY(flm->rowCount() > 0); // read an invalid directory first... flm->setProperty("folder", testFileUrl("nosuchdirectory")); diff --git a/tests/auto/qml/qquickworkerscript/CMakeLists.txt b/tests/auto/qml/qquickworkerscript/CMakeLists.txt index 52a2380ff4..94473d9032 100644 --- a/tests/auto/qml/qquickworkerscript/CMakeLists.txt +++ b/tests/auto/qml/qquickworkerscript/CMakeLists.txt @@ -12,16 +12,14 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qquickworkerscript SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qquickworkerscript.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate Qt::QmlWorkerScriptPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp index b093dcaf07..e410bf75a3 100644 --- a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp +++ b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp @@ -38,13 +38,13 @@ #include <private/qquickworkerscript_p.h> #include <private/qqmlengine_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_QQuickWorkerScript : public QQmlDataTest { Q_OBJECT public: - tst_QQuickWorkerScript() {} + tst_QQuickWorkerScript() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void source(); void ready(); diff --git a/tests/auto/qml/qtqmlmodules/CMakeLists.txt b/tests/auto/qml/qtqmlmodules/CMakeLists.txt index 9637588a8b..6ff0cc01ae 100644 --- a/tests/auto/qml/qtqmlmodules/CMakeLists.txt +++ b/tests/auto/qml/qtqmlmodules/CMakeLists.txt @@ -12,18 +12,20 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qtqmlmodules SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qtqmlmodules.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::CorePrivate Qt::Gui Qt::GuiPrivate Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) +if(QT_BUILD_STANDALONE_TESTS) + qt_import_qml_plugins(tst_qtqmlmodules) +endif() + ## Scopes: ##################################################################### diff --git a/tests/auto/qml/qtqmlmodules/tst_qtqmlmodules.cpp b/tests/auto/qml/qtqmlmodules/tst_qtqmlmodules.cpp index 90b6feee28..874d6fe102 100644 --- a/tests/auto/qml/qtqmlmodules/tst_qtqmlmodules.cpp +++ b/tests/auto/qml/qtqmlmodules/tst_qtqmlmodules.cpp @@ -30,13 +30,13 @@ #include <QDebug> #include <QQmlEngine> #include <QQmlComponent> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qtqmlmodules : public QQmlDataTest { Q_OBJECT public: - tst_qtqmlmodules() {} + tst_qtqmlmodules() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void baseTypes(); diff --git a/tests/auto/qml/qv4assembler/CMakeLists.txt b/tests/auto/qml/qv4assembler/CMakeLists.txt index 1f73fd3495..486baf7deb 100644 --- a/tests/auto/qml/qv4assembler/CMakeLists.txt +++ b/tests/auto/qml/qv4assembler/CMakeLists.txt @@ -12,13 +12,11 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qv4assembler SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qv4assembler.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp index d6bee0c96c..5667b7b8af 100644 --- a/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp +++ b/tests/auto/qml/qv4assembler/tst_qv4assembler.cpp @@ -26,13 +26,12 @@ ** ****************************************************************************/ -#include <util.h> - #include <QtTest/QtTest> #include <QtCore/qprocess.h> #include <QtCore/qtemporaryfile.h> #include <QtQml/qqml.h> #include <QtQml/qqmlapplicationengine.h> +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <private/qv4global_p.h> @@ -44,6 +43,9 @@ class tst_QV4Assembler : public QQmlDataTest { Q_OBJECT +public: + tst_QV4Assembler(); + private slots: void initTestCase() override; void perfMapFile(); @@ -51,6 +53,11 @@ private slots: void jitEnabled(); }; +tst_QV4Assembler::tst_QV4Assembler() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_QV4Assembler::initTestCase() { qputenv("QV4_JIT_CALL_THRESHOLD", "0"); @@ -145,6 +152,9 @@ void tst_QV4Assembler::jitEnabled() #if defined(Q_OS_IOS) || defined(Q_OS_TVOS) /* JIT should be disabled on iOS and tvOS. */ QVERIFY(!QT_CONFIG(qml_jit)); +#elif defined(Q_OS_ANDROID) && defined(Q_PROCESSOR_ARM) + /* JIT is disabled for Android on ARM/ARM64 before Qt 6.4, see QTBUG-102776. */ + QVERIFY(!QT_CONFIG(qml_jit)); #elif defined(Q_OS_WIN) && defined(Q_PROCESSOR_ARM) /* JIT should be disabled Windows on ARM/ARM64 for now. */ QVERIFY(!QT_CONFIG(qml_jit)); diff --git a/tests/auto/qml/qv4mm/CMakeLists.txt b/tests/auto/qml/qv4mm/CMakeLists.txt index f5667c2b5d..93e71ac0c9 100644 --- a/tests/auto/qml/qv4mm/CMakeLists.txt +++ b/tests/auto/qml/qv4mm/CMakeLists.txt @@ -12,14 +12,12 @@ list(APPEND test_data ${test_data_glob}) qt_internal_add_test(tst_qv4mm SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qv4mm.cpp - INCLUDE_DIRECTORIES - ../../shared PUBLIC_LIBRARIES Qt::Gui Qt::Qml Qt::QmlPrivate + Qt::QuickTestUtilsPrivate TESTDATA ${test_data} ) diff --git a/tests/auto/qml/qv4mm/tst_qv4mm.cpp b/tests/auto/qml/qv4mm/tst_qv4mm.cpp index b6a5753e56..fe2e267cfd 100644 --- a/tests/auto/qml/qv4mm/tst_qv4mm.cpp +++ b/tests/auto/qml/qv4mm/tst_qv4mm.cpp @@ -35,7 +35,7 @@ #include <private/qv4qobjectwrapper_p.h> #include <private/qjsvalue_p.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> #include <memory> @@ -43,14 +43,22 @@ class tst_qv4mm : public QQmlDataTest { Q_OBJECT +public: + tst_qv4mm(); + private slots: void gcStats(); void multiWrappedQObjects(); void accessParentOnDestruction(); - void clearICParent(); + void cleanInternalClasses(); void createObjectsOnDestruction(); }; +tst_qv4mm::tst_qv4mm() + : QQmlDataTest(QT_QMLTEST_DATADIR) +{ +} + void tst_qv4mm::gcStats() { QLoggingCategory::setFilterRules("qt.qml.gc.*=true"); @@ -77,10 +85,10 @@ void tst_qv4mm::multiWrappedQObjects() QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 1); QCOMPARE(engine2.memoryManager->m_pendingFreedObjectWrapperValue.size(), 0); - // Moves the additional WeakValue from m_multiplyWrappedQObjects to - // m_pendingFreedObjectWrapperValue. It's still alive after all. + // The additional WeakValue from m_multiplyWrappedQObjects hasn't been moved + // to m_pendingFreedObjectWrapperValue yet. It's still alive after all. engine1.memoryManager->runGC(); - QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 2); + QCOMPARE(engine1.memoryManager->m_pendingFreedObjectWrapperValue.size(), 1); // engine2 doesn't own the object as engine1 was the first to wrap it above. // Therefore, no effect here. @@ -111,16 +119,41 @@ void tst_qv4mm::accessParentOnDestruction() QCOMPARE(obj->property("destructions").toInt(), 100); } -void tst_qv4mm::clearICParent() +void tst_qv4mm::cleanInternalClasses() { QV4::ExecutionEngine engine; QV4::Scope scope(engine.rootContext()); QV4::ScopedObject object(scope, engine.newObject()); + QV4::ScopedObject prototype(scope, engine.newObject()); + + // Set a prototype so that we get a unique IC. + object->setPrototypeOf(prototype); + + QV4::Scoped<QV4::InternalClass> prevIC(scope, object->internalClass()); + QVERIFY(prevIC->d()->transitions.empty()); + + uint prevIcChainLength = 0; + for (QV4::Heap::InternalClass *ic = object->internalClass(); ic; ic = ic->parent) + ++prevIcChainLength; + + const auto checkICCHainLength = [&]() { + uint icChainLength = 0; + for (QV4::Heap::InternalClass *ic = object->internalClass(); ic; ic = ic->parent) + ++icChainLength; + + const uint redundant = object->internalClass()->numRedundantTransitions; + QVERIFY(redundant <= QV4::Heap::InternalClass::MaxRedundantTransitions); + + // A removal makes two transitions redundant. + QVERIFY(icChainLength <= prevIcChainLength + 2 * redundant); + }; + + const uint numTransitions = 16 * 1024; // 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) { + for (uint i = 0; i < numTransitions; ++i) { QV4::Scope scope(&engine); QV4::ScopedString s(scope); s = engine.newIdentifier(QString::fromLatin1("key%1").arg(i)); @@ -131,22 +164,60 @@ void tst_qv4mm::clearICParent() 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) { + // There is a chain of ICs originating from the original class. + QCOMPARE(prevIC->d()->transitions.size(), 1u); + QVERIFY(prevIC->d()->transitions.front().lookup != nullptr); + + // When allocating the InternalClass objects required for deleting properties, eventually + // the IC chain gets truncated, dropping all the removed properties. + for (uint i = 0; i < numTransitions; ++i) { QV4::Scope scope(&engine); QV4::ScopedString s(scope, identifiers->get(i)); QV4::Scoped<QV4::InternalClass> ic(scope, object->internalClass()); QVERIFY(ic->d()->parent != nullptr); - object->deleteProperty(s->toPropertyKey()); + QV4::ScopedValue val(scope, object->get(s->toPropertyKey())); + QCOMPARE(val->toNumber(), double(i)); + QVERIFY(object->deleteProperty(s->toPropertyKey())); + QVERIFY(!object->hasProperty(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"); + + // None of the properties we've added are left + for (uint i = 0; i < numTransitions; ++i) { + QV4::ScopedString s(scope, identifiers->get(i)); + QVERIFY(!object->hasProperty(s->toPropertyKey())); + } + + // Also no other properties have appeared + QScopedPointer<QV4::OwnPropertyKeyIterator> iterator(object->ownPropertyKeys(object)); + QVERIFY(!iterator->next(object).isValid()); + + checkICCHainLength(); + + // Add and remove properties until it clears all remaining redundant ones + uint i = 0; + while (object->internalClass()->numRedundantTransitions > 0) { + i = (i + 1) % numTransitions; + QV4::ScopedString s(scope, identifiers->get(i)); + QV4::ScopedValue v(scope); + v->setDouble(i); + object->insertMember(s, v); + QVERIFY(object->deleteProperty(s->toPropertyKey())); + } + + // Make sure that all dangling ICs are actually gone. + scope.engine->memoryManager->runGC(); + + // Now the GC has removed the ICs we originally added by adding properties. + QVERIFY(prevIC->d()->transitions.empty() || prevIC->d()->transitions.front().lookup == nullptr); + + // Same thing with redundant prototypes + for (uint i = 0; i < numTransitions; ++i) { + QV4::ScopedObject prototype(scope, engine.newObject()); + object->setPrototypeOf(prototype); // Makes previous prototype redundant + } + + checkICCHainLength(); } void tst_qv4mm::createObjectsOnDestruction() diff --git a/tests/auto/qml/registrationmacros/CMakeLists.txt b/tests/auto/qml/registrationmacros/CMakeLists.txt index 6ac5d4506c..3e01ae34c8 100644 --- a/tests/auto/qml/registrationmacros/CMakeLists.txt +++ b/tests/auto/qml/registrationmacros/CMakeLists.txt @@ -14,4 +14,4 @@ set_target_properties(tst_registrationmacros PROPERTIES QT_QML_MODULE_URI test ) -qt6_qml_type_registration(tst_registrationmacros) +_qt_internal_qml_type_registration(tst_registrationmacros) diff --git a/tests/auto/qml/v4misc/tst_v4misc.cpp b/tests/auto/qml/v4misc/tst_v4misc.cpp index 2412ca7f92..c505396265 100644 --- a/tests/auto/qml/v4misc/tst_v4misc.cpp +++ b/tests/auto/qml/v4misc/tst_v4misc.cpp @@ -177,6 +177,10 @@ void tst_v4misc::subClassing() void tst_v4misc::nestingDepth() { +#ifdef Q_OS_ANDROID + QSKIP("tst_v4misc::nestingDepth crashes on Android, see QTBUG-103743."); +#endif + { // left recursive QString s(40000, '`'); |