diff options
Diffstat (limited to 'tests/auto/qml')
155 files changed, 3734 insertions, 1723 deletions
diff --git a/tests/auto/qml/bindingdependencyapi/bindingdependencyapi.pro b/tests/auto/qml/bindingdependencyapi/bindingdependencyapi.pro new file mode 100644 index 0000000000..430d87ab5b --- /dev/null +++ b/tests/auto/qml/bindingdependencyapi/bindingdependencyapi.pro @@ -0,0 +1,11 @@ +CONFIG += testcase +TARGET = tst_bindingdependencyapi +macos:CONFIG -= app_bundle + +SOURCES += tst_bindingdependencyapi.cpp + +include (../../shared/util.pri) + +TESTDATA = data/* + +QT += core-private gui-private qml-private quick-private testlib diff --git a/tests/auto/qml/bindingdependencyapi/tst_bindingdependencyapi.cpp b/tests/auto/qml/bindingdependencyapi/tst_bindingdependencyapi.cpp new file mode 100644 index 0000000000..6f24f85f6d --- /dev/null +++ b/tests/auto/qml/bindingdependencyapi/tst_bindingdependencyapi.cpp @@ -0,0 +1,360 @@ +/**************************************************************************** +** +** Copyright (C) 2016 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 <qtest.h> +#include <QtQml/qqmlengine.h> +#include <QtQml/qqmlcomponent.h> +#include <private/qqmldata_p.h> +#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 +{ + Q_OBJECT +public: + tst_bindingdependencyapi(); + +private slots: + void testSingleDep_data(); + void testSingleDep(); + void testManyDeps_data(); + void testManyDeps(); + void testConditionalDependencies_data(); + void testConditionalDependencies(); + void testBindingLoop(); + +private: + bool findProperties(const QVector<QQmlProperty> &properties, QObject *obj, const QString &propertyName, const QVariant &value); +}; + +tst_bindingdependencyapi::tst_bindingdependencyapi() +{ +} + + +void tst_bindingdependencyapi::testSingleDep_data() +{ + QTest::addColumn<QByteArray>("code"); + QTest::addColumn<QString>("referencedObjectName"); + + QTest::addRow("context property") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "objectName: \"rect\"\n" + "property string labelText: \"Hello world!\"\n" + "Text { text: labelText }\n" + "}") << "rect"; + + QTest::addRow("scope property") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "property string labelText: \"I am wrong!\"\n" + "Text {\n" + "objectName: \"text\"\n" + "property string labelText: \"Hello world!\"\n" + "text: labelText\n" + "}\n" + "}") << "text"; + + QTest::addRow("id object property") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "id: rect\n" + "objectName: \"rect\"\n" + "property string labelText: \"Hello world!\"\n" + "Text { text: rect.labelText }\n" + "}") << "rect"; + + QTest::addRow("dynamic context property") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "objectName: \"rect\"\n" + "property string labelText: \"Hello world!\"\n" + "Text { Component.onCompleted: text = Qt.binding(function() { return labelText; }); }\n" + "}") << "rect"; + + QTest::addRow("dynamic scope property") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "property string labelText: \"I am wrong!\"\n" + "Text {\n" + "objectName: \"text\"\n" + "property string labelText: \"Hello world!\"\n" + "Component.onCompleted: text = Qt.binding(function() { return labelText; });\n" + "}\n" + "}") << "text"; + + QTest::addRow("dynamic id object property") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "id: rect\n" + "objectName: \"rect\"\n" + "property string labelText: \"Hello world!\"\n" + "Text { Component.onCompleted: text = Qt.binding(function() { return rect.labelText; }); }\n" + "}") << "rect"; +} + +void tst_bindingdependencyapi::testSingleDep() +{ + QFETCH(QByteArray, code); + QFETCH(QString, referencedObjectName); + + QQmlEngine engine; + QQmlComponent c(&engine); + c.setData(code, QUrl()); + QObject *rect = c.create(); + QTest::qWait(10); + QVERIFY(rect != 0); + QObject *text = rect->findChildren<QQuickText *>().front(); + + QObject *referencedObject = rect->objectName() == referencedObjectName ? rect : rect->findChild<QObject *>(referencedObjectName); + + 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(referencedObject)); + QCOMPARE(dependency.property().name(), "labelText"); + QCOMPARE(dependency.read().toString(), QStringLiteral("Hello world!")); + QCOMPARE(dependency, QQmlProperty(referencedObject, "labelText")); + + delete rect; +} + +bool tst_bindingdependencyapi::findProperties(const QVector<QQmlProperty> &properties, QObject *obj, const QString &propertyName, const QVariant &value) +{ + auto dep = std::find_if(properties.cbegin(), properties.cend(), [&](const QQmlProperty &dep) { + return dep.object() == obj + && dep.property().name() == propertyName + && dep.read() == value; + }); + if (dep == properties.cend()) { + qWarning() << "Searched for property with:" << "{ object:" << obj << ", propertyName:" << propertyName << ", value:" << value << "}" << "but only found:"; + for (auto dep : properties) { + qWarning() << "{ object:" << dep.object() << ", propertyName:" << dep.property().name() << ", value:" << dep.read() << "}"; + } + return false; + } + return true; +} + +void tst_bindingdependencyapi::testManyDeps_data() +{ + QTest::addColumn<QByteArray>("code"); + + QTest::addRow("permanent binding") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "id: rect\n" + "objectName: 'rect'\n" + "property string name: 'world'\n" + "Text {\n" + "text: config.helloWorldTemplate.arg(greeting).arg(rect.name) \n" + "property string greeting: 'Hello'\n" + "}\n" + "QtObject { id: config; objectName: 'config'; property string helloWorldTemplate: '%1 %2!' }\n" + "}"); + + QTest::addRow("dynamic binding") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "id: rect\n" + "objectName: 'rect'\n" + "property string name: 'world'\n" + "Text {\n" + "Component.onCompleted: text = Qt.binding(function() { return config.helloWorldTemplate.arg(greeting).arg(rect.name); }); \n" + "property string greeting: 'Hello'\n" + "}\n" + "QtObject { id: config; objectName: 'config'; property string helloWorldTemplate: '%1 %2!' }\n" + "}"); +} + +void tst_bindingdependencyapi::testManyDeps() +{ + QFETCH(QByteArray, code); + QQmlEngine engine; + QQmlComponent c(&engine); + c.setData(code, QUrl()); + QObject *rect = c.create(); + if (c.isError()) { + qWarning() << c.errorString(); + } + QTest::qWait(100); + QVERIFY(rect != 0); + QObject *text = rect->findChildren<QQuickText *>().front(); + QObject *configObj = rect->findChild<QObject *>("config"); + + 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(), 3); + + QVERIFY(findProperties(dependencies, rect, "name", "world")); + QVERIFY(findProperties(dependencies, text, "greeting", "Hello")); + QVERIFY(findProperties(dependencies, configObj, "helloWorldTemplate", "%1 %2!")); + + delete rect; +} + +void tst_bindingdependencyapi::testConditionalDependencies_data() +{ + QTest::addColumn<QByteArray>("code"); + QTest::addColumn<QString>("referencedObjectName"); + + QTest::addRow("id object property") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "id: rect\n" + "objectName: \"rect\"\n" + "property bool haveDep: false\n" + "property string labelText: \"Hello world!\"\n" + "Text { text: rect.haveDep ? rect.labelText : '' }\n" + "}") << "rect"; + + QTest::addRow("dynamic context property") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "objectName: \"rect\"\n" + "property bool haveDep: false\n" + "property string labelText: \"Hello world!\"\n" + "Text { Component.onCompleted: text = Qt.binding(function() { return haveDep ? labelText : ''; }); }\n" + "}") << "rect"; + + QTest::addRow("dynamic scope property") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "property string labelText: \"I am wrong!\"\n" + "Text {\n" + "objectName: \"text\"\n" + "property bool haveDep: false\n" + "property string labelText: \"Hello world!\"\n" + "Component.onCompleted: text = Qt.binding(function() { return haveDep ? labelText : ''; });\n" + "}\n" + "}") << "text"; + + QTest::addRow("dynamic id object property") + << QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "id: rect\n" + "objectName: \"rect\"\n" + "property bool haveDep: false\n" + "property string labelText: \"Hello world!\"\n" + "Text { Component.onCompleted: text = Qt.binding(function() { return rect.haveDep ? rect.labelText : ''; }); }\n" + "}") << "rect"; +} + +void tst_bindingdependencyapi::testConditionalDependencies() +{ + QFETCH(QByteArray, code); + QFETCH(QString, referencedObjectName); + + QQmlEngine engine; + QQmlComponent c(&engine); + c.setData(code, QUrl()); + QObject *rect = c.create(); + QTest::qWait(10); + QVERIFY(rect != 0); + QObject *text = rect->findChildren<QQuickText *>().front(); + + QObject *referencedObject = rect->objectName() == referencedObjectName ? rect : rect->findChild<QObject *>(referencedObjectName); + + 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); + QVERIFY(findProperties(dependencies, referencedObject, "haveDep", false)); + + referencedObject->setProperty("haveDep", true); + dependencies = binding->dependencies(); + QCOMPARE(dependencies.size(), 2); + QVERIFY(findProperties(dependencies, referencedObject, "haveDep", true)); + QVERIFY(findProperties(dependencies, referencedObject, "labelText", "Hello world!")); + + referencedObject->setProperty("haveDep", false); + dependencies = binding->dependencies(); + QCOMPARE(dependencies.size(), 1); + QVERIFY(findProperties(dependencies, referencedObject, "haveDep", false)); + + delete rect; +} + +void tst_bindingdependencyapi::testBindingLoop() +{ + QQmlEngine engine; + QQmlComponent c(&engine); + c.setData(QByteArray("import QtQuick 2.0\n" + "Rectangle {\n" + "property string labelText: label.text\n" + "Text {\n" + "id: label\n" + "text: labelText\n" + "}\n" + "}"), QUrl()); + QObject *rect = c.create(); + if (c.isError()) { + qWarning() << c.errorString(); + } + QTest::qWait(100); + QVERIFY(rect != 0); + QObject *text = rect->findChildren<QQuickText *>().front(); + + 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(rect)); + QCOMPARE(dependency.property().name(), "labelText"); + + delete rect; +} + +QTEST_MAIN(tst_bindingdependencyapi) + +#include "tst_bindingdependencyapi.moc" diff --git a/tests/auto/qml/debugger/debugger.pro b/tests/auto/qml/debugger/debugger.pro index a50411e18b..63721cc575 100644 --- a/tests/auto/qml/debugger/debugger.pro +++ b/tests/auto/qml/debugger/debugger.pro @@ -10,7 +10,8 @@ PUBLICTESTS += \ qqmlenginedebuginspectorintegrationtest \ qqmlenginecontrol \ qqmldebuggingenabler \ - qqmlnativeconnector + qqmlnativeconnector \ + qqmldebugprocess PRIVATETESTS += \ qqmldebugclient \ diff --git a/tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro b/tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro index 6c729ab235..9cf323ba36 100644 --- a/tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro +++ b/tests/auto/qml/debugger/qdebugmessageservice/qdebugmessageservice.pro @@ -5,8 +5,6 @@ osx:CONFIG -= app_bundle SOURCES += tst_qdebugmessageservice.cpp -INCLUDEPATH += ../shared -include(../../../shared/util.pri) include(../shared/debugutil.pri) TESTDATA = data/* diff --git a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp index f193d3928a..f851688b5e 100644 --- a/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp +++ b/tests/auto/qml/debugger/qdebugmessageservice/tst_qdebugmessageservice.cpp @@ -28,7 +28,6 @@ //QQmlDebugTest #include "debugutil_p.h" -#include "../../../shared/util.h" #include <private/qqmldebugclient_p.h> #include <private/qqmldebugconnection_p.h> @@ -38,31 +37,19 @@ #include <QtCore/qlibraryinfo.h> #include <QtTest/qtest.h> -const char *NORMALMODE = "-qmljsdebugger=port:3777,3787,block"; const char *QMLFILE = "test.qml"; class QQmlDebugMsgClient; -class tst_QDebugMessageService : public QQmlDataTest +class tst_QDebugMessageService : public QQmlDebugTest { Q_OBJECT -public: - tst_QDebugMessageService(); - - void init(); - private slots: - void initTestCase(); - void cleanupTestCase(); - - void cleanup(); - void retrieveDebugOutput(); private: - QQmlDebugProcess *m_process; - QQmlDebugMsgClient *m_client; - QQmlDebugConnection *m_connection; + QList<QQmlDebugClient *> createClients() override; + QPointer<QQmlDebugMsgClient> m_client; }; struct LogEntry { @@ -150,73 +137,16 @@ void QQmlDebugMsgClient::messageReceived(const QByteArray &data) } } -tst_QDebugMessageService::tst_QDebugMessageService() -{ -} - -void tst_QDebugMessageService::initTestCase() -{ - QQmlDataTest::initTestCase(); - m_process = 0; - m_client = 0; - m_connection = 0; -} - -void tst_QDebugMessageService::cleanupTestCase() +QList<QQmlDebugClient *> tst_QDebugMessageService::createClients() { - if (m_process) - delete m_process; - - if (m_client) - delete m_client; - - if (m_connection) - delete m_connection; -} - -void tst_QDebugMessageService::init() -{ - m_connection = new QQmlDebugConnection(); - m_process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml", this); m_client = new QQmlDebugMsgClient(m_connection); - - m_process->start(QStringList() << QLatin1String(NORMALMODE) << QQmlDataTest::instance()->testFile(QMLFILE)); - QVERIFY2(m_process->waitForSessionStart(), - "Could not launch application, or did not get 'Waiting for connection'."); - - const int port = m_process->debugPort(); - m_connection->connectToHost("127.0.0.1", port); - QVERIFY(m_connection->waitForConnected()); - - if (m_client->state() != QQmlDebugClient::Enabled) - QQmlDebugTest::waitForSignal(m_client, SIGNAL(enabled())); - - QCOMPARE(m_client->state(), QQmlDebugClient::Enabled); -} - -void tst_QDebugMessageService::cleanup() -{ - if (QTest::currentTestFailed()) { - qDebug() << "Process State:" << m_process->state(); - qDebug() << "Application Output:" << m_process->output(); - } - if (m_process) - delete m_process; - - if (m_client) - delete m_client; - - if (m_connection) - delete m_connection; - - m_process = 0; - m_client = 0; - m_connection = 0; + return QList<QQmlDebugClient *>({m_client}); } void tst_QDebugMessageService::retrieveDebugOutput() { - init(); + QCOMPARE(QQmlDebugTest::connect(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml", + QString(), testFile(QMLFILE), true), ConnectSuccess); QTRY_VERIFY(m_client->logBuffer.size() >= 2); diff --git a/tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro b/tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro index a7c0fa7f8e..b1e3835844 100644 --- a/tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro +++ b/tests/auto/qml/debugger/qpacketprotocol/qpacketprotocol.pro @@ -4,7 +4,6 @@ osx:CONFIG -= app_bundle SOURCES += tst_qpacketprotocol.cpp -INCLUDEPATH += ../shared include(../shared/debugutil.pri) QT += qml network testlib gui-private core-private diff --git a/tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro b/tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro index 622b373692..673330a3cf 100644 --- a/tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro +++ b/tests/auto/qml/debugger/qqmldebugclient/qqmldebugclient.pro @@ -7,7 +7,6 @@ HEADERS += ../shared/qqmldebugtestservice.h SOURCES += tst_qqmldebugclient.cpp \ ../shared/qqmldebugtestservice.cpp -INCLUDEPATH += ../shared include(../shared/debugutil.pri) DEFINES += QT_QML_DEBUG_NO_WARNING diff --git a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/qqmldebuggingenabler.pro b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/qqmldebuggingenabler.pro index f8014f04f4..bd382ebaab 100644 --- a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/qqmldebuggingenabler.pro +++ b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/qqmldebuggingenabler.pro @@ -6,8 +6,6 @@ osx:CONFIG -= app_bundle SOURCES += tst_qqmldebuggingenabler.cpp -INCLUDEPATH += ../../shared -include(../../../../shared/util.pri) include(../../shared/debugutil.pri) OTHER_FILES += data/test.qml diff --git a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp index 3aa3a5c87e..a76740a3f9 100644 --- a/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp +++ b/tests/auto/qml/debugger/qqmldebuggingenabler/qqmldebuggingenabler/tst_qqmldebuggingenabler.cpp @@ -27,11 +27,14 @@ ****************************************************************************/ #include "debugutil_p.h" +#include "qqmldebugprocess_p.h" #include "../../../shared/util.h" #include <private/qqmldebugclient_p.h> #include <private/qqmldebugconnection_p.h> +#include <QtQml/qqmldebug.h> + #include <QtTest/qtest.h> #include <QtCore/qprocess.h> #include <QtCore/qtimer.h> @@ -40,17 +43,11 @@ #include <QtCore/qmutex.h> #include <QtCore/qlibraryinfo.h> -class tst_QQmlDebuggingEnabler : public QQmlDataTest +class tst_QQmlDebuggingEnabler : public QQmlDebugTest { Q_OBJECT - bool init(bool blockMode, bool qmlscene, int portFrom, int portTo); - private slots: - void initTestCase(); - void cleanupTestCase(); - void cleanup(); - void qmlscene_data(); void qmlscene(); void custom_data(); @@ -58,88 +55,8 @@ private slots: private: void data(); - QQmlDebugProcess *process; - QQmlDebugConnection *connection; - QTime t; }; -void tst_QQmlDebuggingEnabler::initTestCase() -{ - QQmlDataTest::initTestCase(); - t.start(); - process = 0; - connection = 0; -} - -void tst_QQmlDebuggingEnabler::cleanupTestCase() -{ - if (process) { - process->stop(); - delete process; - } - - if (connection) - delete connection; -} - -bool tst_QQmlDebuggingEnabler::init(bool blockMode, bool qmlscene, int portFrom, int portTo) -{ - connection = new QQmlDebugConnection(); - - if (qmlscene) { - process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this); - process->setMaximumBindErrors(1); - } else { - process = new QQmlDebugProcess(QCoreApplication::applicationDirPath() + QLatin1String("/qqmldebuggingenablerserver"), this); - process->setMaximumBindErrors(portTo - portFrom); - } - - if (qmlscene) { - process->start(QStringList() << QLatin1String("-qmljsdebugger=port:") + - QString::number(portFrom) + QLatin1Char(',') + QString::number(portTo) + - QLatin1String(blockMode ? ",block": "") << - testFile(QLatin1String("test.qml"))); - } else { - QStringList args; - if (blockMode) - args << QLatin1String("-block"); - args << QString::number(portFrom) << QString::number(portTo); - process->start(args); - } - - if (!process->waitForSessionStart()) { - return false; - } - - const int port = process->debugPort(); - connection->connectToHost("127.0.0.1", port); - if (!connection->waitForConnected()) { - qDebug() << "could not connect to host!"; - return false; - } - return true; -} - -void tst_QQmlDebuggingEnabler::cleanup() -{ - if (QTest::currentTestFailed()) { - qDebug() << "Process State:" << process->state(); - qDebug() << "Application Output:" << process->output(); - } - - if (process) { - process->stop(); - delete process; - } - - - if (connection) - delete connection; - - process = 0; - connection = 0; -} - void tst_QQmlDebuggingEnabler::data() { QTest::addColumn<QString>("connector"); @@ -185,32 +102,32 @@ void tst_QQmlDebuggingEnabler::qmlscene() QFETCH(bool, blockMode); QFETCH(QStringList, services); - process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", - this); - process->setMaximumBindErrors(1); - process->start(QStringList() - << QString::fromLatin1("-qmljsdebugger=connector:%1%2%3%4") - .arg(connector + (connector == QLatin1String("QQmlDebugServer") ? - QLatin1String(",port:5555,5565") : QString())) - .arg(blockMode ? QLatin1String(",block") : QString()) - .arg(services.isEmpty() ? QString() : QString::fromLatin1(",services:")) - .arg(services.isEmpty() ? QString() : services.join(",")) - << testFile(QLatin1String("test.qml"))); + m_process = new QQmlDebugProcess( + QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this); + m_process->setMaximumBindErrors(1); + m_process->start(QStringList() + << QString::fromLatin1("-qmljsdebugger=connector:%1%2%3%4") + .arg(connector + (connector == QLatin1String("QQmlDebugServer") + ? QLatin1String(",port:5555,5565") : QString())) + .arg(blockMode ? QLatin1String(",block") : QString()) + .arg(services.isEmpty() ? QString() : QString::fromLatin1(",services:")) + .arg(services.isEmpty() ? QString() : services.join(",")) + << testFile(QLatin1String("test.qml"))); if (connector == QLatin1String("QQmlDebugServer")) { - QVERIFY(process->waitForSessionStart()); - connection = new QQmlDebugConnection(); - QList<QQmlDebugClient *> clients = QQmlDebugTest::createOtherClients(connection); - connection->connectToHost("127.0.0.1", process->debugPort()); - QVERIFY(connection->waitForConnected()); - foreach (QQmlDebugClient *client, clients) + QVERIFY(m_process->waitForSessionStart()); + m_connection = new QQmlDebugConnection(); + m_clients = QQmlDebugTest::createOtherClients(m_connection); + m_connection->connectToHost("127.0.0.1", m_process->debugPort()); + QVERIFY(m_connection->waitForConnected()); + foreach (QQmlDebugClient *client, m_clients) QCOMPARE(client->state(), (services.isEmpty() || services.contains(client->name())) ? QQmlDebugClient::Enabled : QQmlDebugClient::Unavailable); } - QCOMPARE(process->state(), QLatin1String("running")); + QCOMPARE(m_process->state(), QLatin1String("running")); if (!blockMode) - QTRY_VERIFY(process->output().contains(QLatin1String("qml: Component.onCompleted"))); + QTRY_VERIFY(m_process->output().contains(QLatin1String("qml: Component.onCompleted"))); } void tst_QQmlDebuggingEnabler::custom_data() @@ -226,9 +143,9 @@ void tst_QQmlDebuggingEnabler::custom() const int portFrom = 5555; const int portTo = 5565; - process = new QQmlDebugProcess(QCoreApplication::applicationDirPath() + - QLatin1String("/qqmldebuggingenablerserver"), this); - process->setMaximumBindErrors(portTo - portFrom); + m_process = new QQmlDebugProcess(QCoreApplication::applicationDirPath() + + QLatin1String("/qqmldebuggingenablerserver"), this); + m_process->setMaximumBindErrors(portTo - portFrom); QStringList args; if (blockMode) @@ -240,22 +157,22 @@ void tst_QQmlDebuggingEnabler::custom() if (!services.isEmpty()) args << QLatin1String("-services") << services; - process->start(args); + m_process->start(args); if (connector == QLatin1String("QQmlDebugServer")) { - QVERIFY(process->waitForSessionStart()); - connection = new QQmlDebugConnection(); - QList<QQmlDebugClient *> clients = QQmlDebugTest::createOtherClients(connection); - connection->connectToHost("127.0.0.1", process->debugPort()); - QVERIFY(connection->waitForConnected()); - foreach (QQmlDebugClient *client, clients) + QVERIFY(m_process->waitForSessionStart()); + m_connection = new QQmlDebugConnection(); + m_clients = QQmlDebugTest::createOtherClients(m_connection); + m_connection->connectToHost("127.0.0.1", m_process->debugPort()); + QVERIFY(m_connection->waitForConnected()); + for (QQmlDebugClient *client : qAsConst(m_clients)) QCOMPARE(client->state(), (services.isEmpty() || services.contains(client->name())) ? QQmlDebugClient::Enabled : QQmlDebugClient::Unavailable); } - QCOMPARE(process->state(), QLatin1String("running")); + QCOMPARE(m_process->state(), QLatin1String("running")); if (!blockMode) - QTRY_VERIFY(process->output().contains(QLatin1String("QQmlEngine created"))); + QTRY_VERIFY(m_process->output().contains(QLatin1String("QQmlEngine created"))); } QTEST_MAIN(tst_QQmlDebuggingEnabler) diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro index cbaf3b5309..90623c75a6 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro +++ b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/qqmldebugjs.pro @@ -6,8 +6,6 @@ osx:CONFIG -= app_bundle SOURCES += tst_qqmldebugjs.cpp -INCLUDEPATH += ../../shared -include(../../../../shared/util.pri) include(../../shared/debugutil.pri) include(../../shared/qqmlenginedebugclient.pri) diff --git a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp index d248cf9708..3cd359cf48 100644 --- a/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp +++ b/tests/auto/qml/debugger/qqmldebugjs/qqmldebugjs/tst_qqmldebugjs.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include "debugutil_p.h" +#include "qqmldebugprocess_p.h" #include "../../shared/qqmlenginedebugclient.h" #include "../../../../shared/util.h" @@ -136,7 +137,7 @@ const char *BREAKPOINTRELOCATION_QMLFILE = "breakpointRelocation.qml"; do {\ if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) {\ if (QTest::currentTestFailed()) \ - qDebug().nospace() << "\nDEBUGGEE OUTPUT:\n" << process->output();\ + qDebug().nospace() << "\nDEBUGGEE OUTPUT:\n" << m_process->output();\ return;\ }\ } while (0) @@ -144,18 +145,12 @@ do {\ class QJSDebugClient; -class tst_QQmlDebugJS : public QQmlDataTest +class tst_QQmlDebugJS : public QQmlDebugTest { Q_OBJECT - void init(bool qmlscene, const QString &qmlFile = QString(TEST_QMLFILE), bool blockMode = true, - bool restrictServices = false); - private slots: - void initTestCase(); - void cleanupTestCase(); - - void cleanup(); + void initTestCase() override; void connect_data(); void connect(); @@ -223,11 +218,12 @@ private slots: void getScripts(); private: - void targetData(); + ConnectResult init(bool qmlscene, const QString &qmlFile = QString(TEST_QMLFILE), + bool blockMode = true, bool restrictServices = false); + QList<QQmlDebugClient *> createClients() override; + QPointer<QJSDebugClient> m_client; - QQmlDebugProcess *process; - QJSDebugClient *client; - QQmlDebugConnection *connection; + void targetData(); QTime t; }; @@ -280,7 +276,6 @@ protected: void messageReceived(const QByteArray &data); signals: - void enabled(); void connected(); void interruptRequested(); void result(); @@ -667,10 +662,8 @@ void QJSDebugClient::disconnect() void QJSDebugClient::stateChanged(State state) { - if (state == Enabled) { + if (state == Enabled) flushSendBuffer(); - emit enabled(); - } } void QJSDebugClient::messageReceived(const QByteArray &data) @@ -763,85 +756,19 @@ QByteArray QJSDebugClient::packMessage(const QByteArray &type, const QByteArray void tst_QQmlDebugJS::initTestCase() { - QQmlDataTest::initTestCase(); + QQmlDebugTest::initTestCase(); t.start(); - process = 0; - client = 0; - connection = 0; } -void tst_QQmlDebugJS::cleanupTestCase() +QQmlDebugTest::ConnectResult tst_QQmlDebugJS::init(bool qmlscene, const QString &qmlFile, + bool blockMode, bool restrictServices) { - if (process) { - process->stop(); - delete process; - } - - if (client) - delete client; - - if (connection) - delete connection; -} - -void tst_QQmlDebugJS::init(bool qmlscene, const QString &qmlFile, bool blockMode, - bool restrictServices) -{ - connection = new QQmlDebugConnection(); - if (qmlscene) - process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + - "/qmlscene", this); - else - process = new QQmlDebugProcess(QCoreApplication::applicationDirPath() + - QLatin1String("/qqmldebugjsserver"), this); - client = new QJSDebugClient(connection); - QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(connection); - - const char *args = 0; - if (blockMode) - args = restrictServices ? BLOCKRESTRICTEDMODE : BLOCKMODE; - else - args = restrictServices ? NORMALRESTRICTEDMODE : NORMALMODE; - - process->start(QStringList() << QLatin1String(args) << testFile(qmlFile)); - - QVERIFY(process->waitForSessionStart()); - - const int port = process->debugPort(); - connection->connectToHost("127.0.0.1", port); - QVERIFY(connection->waitForConnected()); - - - if (client->state() != QQmlDebugClient::Enabled) - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(enabled()))); - - foreach (QQmlDebugClient *otherClient, others) - QCOMPARE(otherClient->state(), restrictServices ? QQmlDebugClient::Unavailable : - QQmlDebugClient::Enabled); - qDeleteAll(others); -} - -void tst_QQmlDebugJS::cleanup() -{ - if (QTest::currentTestFailed()) { - qDebug() << "Process State:" << process->state(); - qDebug() << "Application Output:" << process->output(); - } - - if (process) { - process->stop(); - delete process; - } - - if (client) - delete client; - - if (connection) - delete connection; - - process = 0; - client = 0; - connection = 0; + const QString executable = qmlscene + ? QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene" + : QCoreApplication::applicationDirPath() + QLatin1String("/qqmldebugjsserver"); + return QQmlDebugTest::connect( + executable, restrictServices ? QStringLiteral("V8Debugger") : QString(), + testFile(qmlFile), blockMode); } void tst_QQmlDebugJS::connect_data() @@ -864,9 +791,9 @@ void tst_QQmlDebugJS::connect() QFETCH(bool, blockMode); QFETCH(bool, restrictMode); QFETCH(bool, qmlscene); - init(qmlscene, QString(TEST_QMLFILE), blockMode, restrictMode); - client->connect(); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected()))); + QCOMPARE(init(qmlscene, QString(TEST_QMLFILE), blockMode, restrictMode), ConnectSuccess); + m_client->connect(); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(connected()))); } void tst_QQmlDebugJS::interrupt() @@ -876,11 +803,11 @@ void tst_QQmlDebugJS::interrupt() QFETCH(bool, qmlscene); QFETCH(bool, redundantRefs); QFETCH(bool, namesAsObjects); - init(qmlscene); - client->connect(redundantRefs, namesAsObjects); + QCOMPARE(init(qmlscene), ConnectSuccess); + m_client->connect(redundantRefs, namesAsObjects); - client->interrupt(); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(interruptRequested()))); + m_client->interrupt(); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(interruptRequested()))); } void tst_QQmlDebugJS::getVersion() @@ -890,12 +817,12 @@ void tst_QQmlDebugJS::getVersion() QFETCH(bool, qmlscene); QFETCH(bool, redundantRefs); QFETCH(bool, namesAsObjects); - init(qmlscene); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(connected()))); + QCOMPARE(init(qmlscene), ConnectSuccess); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(connected()))); - client->version(); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + m_client->version(); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); } void tst_QQmlDebugJS::getVersionWhenAttaching() @@ -905,11 +832,11 @@ void tst_QQmlDebugJS::getVersionWhenAttaching() QFETCH(bool, redundantRefs); QFETCH(bool, namesAsObjects); - init(qmlscene, QLatin1String(TIMER_QMLFILE), false); - client->connect(redundantRefs, namesAsObjects); + QCOMPARE(init(qmlscene, QLatin1String(TIMER_QMLFILE), false), ConnectSuccess); + m_client->connect(redundantRefs, namesAsObjects); - client->version(); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + m_client->version(); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); } void tst_QQmlDebugJS::disconnect() @@ -919,11 +846,11 @@ void tst_QQmlDebugJS::disconnect() QFETCH(bool, qmlscene); QFETCH(bool, redundantRefs); QFETCH(bool, namesAsObjects); - init(qmlscene); - client->connect(redundantRefs, namesAsObjects); + QCOMPARE(init(qmlscene), ConnectSuccess); + m_client->connect(redundantRefs, namesAsObjects); - client->disconnect(); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + m_client->disconnect(); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); } void tst_QQmlDebugJS::setBreakpointInScriptOnCompleted() @@ -934,14 +861,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnCompleted() QFETCH(bool, namesAsObjects); int sourceLine = 34; - init(qmlscene, ONCOMPLETED_QMLFILE); + QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); @@ -957,14 +884,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnComponentCreated() QFETCH(bool, namesAsObjects); int sourceLine = 34; - init(qmlscene, CREATECOMPONENT_QMLFILE); + QCOMPARE(init(qmlscene, CREATECOMPONENT_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); @@ -978,16 +905,16 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnTimerCallback() QFETCH(bool, redundantRefs); QFETCH(bool, namesAsObjects); int sourceLine = 35; - init(qmlscene, TIMER_QMLFILE); + QCOMPARE(init(qmlscene, TIMER_QMLFILE), ConnectSuccess); - client->connect(redundantRefs, namesAsObjects); + m_client->connect(redundantRefs, namesAsObjects); //We can set the breakpoint after connect() here because the timer is repeating and if we miss //its first iteration we can still catch the second one. - client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine, -1, true); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine, -1, true); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); @@ -1003,14 +930,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptInDifferentFile() QFETCH(bool, namesAsObjects); int sourceLine = 31; - init(qmlscene, LOADJSFILE_QMLFILE); + QCOMPARE(init(qmlscene, LOADJSFILE_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(TEST_JSFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(TEST_JSFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); @@ -1027,15 +954,15 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnComment() int sourceLine = 34; int actualLine = 36; - init(qmlscene, BREAKPOINTRELOCATION_QMLFILE); + QCOMPARE(init(qmlscene, BREAKPOINTRELOCATION_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); + m_client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1)); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()), 1)); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); @@ -1052,15 +979,15 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnEmptyLine() int sourceLine = 35; int actualLine = 36; - init(qmlscene, BREAKPOINTRELOCATION_QMLFILE); + QCOMPARE(init(qmlscene, BREAKPOINTRELOCATION_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); + m_client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); QEXPECT_FAIL("", "Relocation of breakpoints is disabled right now", Abort); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()), 1)); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()), 1)); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); @@ -1076,14 +1003,14 @@ void tst_QQmlDebugJS::setBreakpointInScriptOnOptimizedBinding() QFETCH(bool, namesAsObjects); int sourceLine = 39; - init(qmlscene, BREAKPOINTRELOCATION_QMLFILE); + QCOMPARE(init(qmlscene, BREAKPOINTRELOCATION_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(BREAKPOINTRELOCATION_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); @@ -1098,28 +1025,28 @@ void tst_QQmlDebugJS::setBreakpointInScriptWithCondition() QFETCH(bool, namesAsObjects); int out = 10; int sourceLine = 37; - init(qmlscene, CONDITION_QMLFILE); + QCOMPARE(init(qmlscene, CONDITION_QMLFILE), ConnectSuccess); - client->connect(redundantRefs, namesAsObjects); + m_client->connect(redundantRefs, namesAsObjects); //The breakpoint is in a timer loop so we can set it after connect(). - client->setBreakpoint(QLatin1String(CONDITION_QMLFILE), sourceLine, 1, true, QLatin1String("a > 10")); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(CONDITION_QMLFILE), sourceLine, 1, true, QLatin1String("a > 10")); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); //Get the frame index - QString jsonString = client->response; - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString = m_client->response; + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); { QVariantMap body = value.value("body").toMap(); int frameIndex = body.value("index").toInt(); //Verify the value of 'result' - client->evaluate(QLatin1String("a"),frameIndex); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + m_client->evaluate(QLatin1String("a"),frameIndex); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); } - jsonString = client->response; - QJSValue val = client->parser.call(QJSValueList() << QJSValue(jsonString)); + jsonString = m_client->response; + QJSValue val = m_client->parser.call(QJSValueList() << QJSValue(jsonString)); QVERIFY(val.isObject()); QJSValue body = val.property(QStringLiteral("body")); QVERIFY(body.isObject()); @@ -1135,42 +1062,42 @@ void tst_QQmlDebugJS::setBreakpointInScriptThatQuits() QFETCH(bool, qmlscene); QFETCH(bool, redundantRefs); QFETCH(bool, namesAsObjects); - init(qmlscene, QUIT_QMLFILE); + QCOMPARE(init(qmlscene, QUIT_QMLFILE), ConnectSuccess); int sourceLine = 36; - client->setBreakpoint(QLatin1String(QUIT_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(QUIT_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); QCOMPARE(body.value("sourceLine").toInt(), sourceLine); QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(QUIT_QMLFILE)); - client->continueDebugging(QJSDebugClient::Continue); - QVERIFY(process->waitForFinished()); - QCOMPARE(process->exitStatus(), QProcess::NormalExit); + m_client->continueDebugging(QJSDebugClient::Continue); + QVERIFY(m_process->waitForFinished()); + QCOMPARE(m_process->exitStatus(), QProcess::NormalExit); } void tst_QQmlDebugJS::setBreakpointWhenAttaching() { int sourceLine = 35; - init(true, QLatin1String(TIMER_QMLFILE), false); + QCOMPARE(init(true, QLatin1String(TIMER_QMLFILE), false), ConnectSuccess); - client->connect(); + m_client->connect(); QSKIP("\nThe breakpoint may not hit because the engine may run in JIT mode or not have debug\n" "instructions, as we've connected in non-blocking mode above. That means we may have\n" "connected after the engine was already running, with all the QML already compiled."); //The breakpoint is in a timer loop so we can set it after connect(). - client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine); + m_client->setBreakpoint(QLatin1String(TIMER_QMLFILE), sourceLine); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); } void tst_QQmlDebugJS::clearBreakpoint() @@ -1182,41 +1109,41 @@ void tst_QQmlDebugJS::clearBreakpoint() int sourceLine1 = 37; int sourceLine2 = 38; - init(qmlscene, CHANGEBREAKPOINT_QMLFILE); + QCOMPARE(init(qmlscene, CHANGEBREAKPOINT_QMLFILE), ConnectSuccess); - client->connect(redundantRefs, namesAsObjects); + m_client->connect(redundantRefs, namesAsObjects); //The breakpoints are in a timer loop so we can set them after connect(). //Furthermore the breakpoints should be hit in the right order because setting of breakpoints //can only occur in the QML event loop. (see QCOMPARE for sourceLine2 below) - client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine1, -1, true); - client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine2, -1, true); + m_client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine1, -1, true); + m_client->setBreakpoint(QLatin1String(CHANGEBREAKPOINT_QMLFILE), sourceLine2, -1, true); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); //Will hit 1st brakpoint, change this breakpoint enable = false - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); QList<QVariant> breakpointsHit = body.value("breakpoints").toList(); int breakpoint = breakpointsHit.at(0).toInt(); - client->clearBreakpoint(breakpoint); + m_client->clearBreakpoint(breakpoint); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); //Continue with debugging - client->continueDebugging(QJSDebugClient::Continue); + m_client->continueDebugging(QJSDebugClient::Continue); //Hit 2nd breakpoint - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); //Continue with debugging - client->continueDebugging(QJSDebugClient::Continue); + m_client->continueDebugging(QJSDebugClient::Continue); //Should stop at 2nd breakpoint - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - jsonString = client->response; - value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + jsonString = m_client->response; + value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); body = value.value("body").toMap(); @@ -1230,10 +1157,10 @@ void tst_QQmlDebugJS::setExceptionBreak() QFETCH(bool, redundantRefs); QFETCH(bool, namesAsObjects); - init(qmlscene, EXCEPTION_QMLFILE); - client->setExceptionBreak(QJSDebugClient::All,true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + QCOMPARE(init(qmlscene, EXCEPTION_QMLFILE), ConnectSuccess); + m_client->setExceptionBreak(QJSDebugClient::All,true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); } void tst_QQmlDebugJS::stepNext() @@ -1244,17 +1171,17 @@ void tst_QQmlDebugJS::stepNext() QFETCH(bool, namesAsObjects); int sourceLine = 37; - init(qmlscene, STEPACTION_QMLFILE); + QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - client->continueDebugging(QJSDebugClient::Next); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->continueDebugging(QJSDebugClient::Next); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); @@ -1262,6 +1189,14 @@ void tst_QQmlDebugJS::stepNext() QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE)); } +static QVariantMap responseBody(QJSDebugClient *client) +{ + const QString jsonString(client->response); + const QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)) + .toVariant().toMap(); + return value.value("body").toMap(); +} + void tst_QQmlDebugJS::stepIn() { //void continueDebugging(StepAction stepAction, int stepCount = 1); @@ -1270,21 +1205,18 @@ void tst_QQmlDebugJS::stepIn() QFETCH(bool, namesAsObjects); int sourceLine = 41; - int actualLine = 37; - init(qmlscene, STEPACTION_QMLFILE); - - client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, 1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); - - client->continueDebugging(QJSDebugClient::In); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + int actualLine = 36; + QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, 1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); + QCOMPARE(responseBody(m_client).value("sourceLine").toInt(), sourceLine); - QVariantMap body = value.value("body").toMap(); + m_client->continueDebugging(QJSDebugClient::In); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); + const QVariantMap body = responseBody(m_client); QCOMPARE(body.value("sourceLine").toInt(), actualLine); QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE)); } @@ -1298,20 +1230,17 @@ void tst_QQmlDebugJS::stepOut() int sourceLine = 37; int actualLine = 41; - init(qmlscene, STEPACTION_QMLFILE); + QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); + QCOMPARE(responseBody(m_client).value("sourceLine").toInt(), sourceLine); - client->continueDebugging(QJSDebugClient::Out); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); - - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); - - QVariantMap body = value.value("body").toMap(); + m_client->continueDebugging(QJSDebugClient::Out); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); + const QVariantMap body = responseBody(m_client); QCOMPARE(body.value("sourceLine").toInt(), actualLine); QCOMPARE(QFileInfo(body.value("script").toMap().value("name").toString()).fileName(), QLatin1String(STEPACTION_QMLFILE)); } @@ -1325,18 +1254,18 @@ void tst_QQmlDebugJS::continueDebugging() int sourceLine1 = 41; int sourceLine2 = 38; - init(qmlscene, STEPACTION_QMLFILE); + QCOMPARE(init(qmlscene, STEPACTION_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine1, -1, true); - client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine2, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine1, -1, true); + m_client->setBreakpoint(QLatin1String(STEPACTION_QMLFILE), sourceLine2, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - client->continueDebugging(QJSDebugClient::Continue); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->continueDebugging(QJSDebugClient::Continue); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); @@ -1352,14 +1281,14 @@ void tst_QQmlDebugJS::backtrace() QFETCH(bool, namesAsObjects); int sourceLine = 34; - init(qmlscene, ONCOMPLETED_QMLFILE); + QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - client->backtrace(); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + m_client->backtrace(); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); } void tst_QQmlDebugJS::getFrameDetails() @@ -1370,14 +1299,14 @@ void tst_QQmlDebugJS::getFrameDetails() QFETCH(bool, namesAsObjects); int sourceLine = 34; - init(qmlscene, ONCOMPLETED_QMLFILE); + QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - client->frame(); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + m_client->frame(); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); } void tst_QQmlDebugJS::getScopeDetails() @@ -1388,33 +1317,32 @@ void tst_QQmlDebugJS::getScopeDetails() QFETCH(bool, namesAsObjects); int sourceLine = 34; - init(qmlscene, ONCOMPLETED_QMLFILE); + QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - client->scope(); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + m_client->scope(); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); } void tst_QQmlDebugJS::evaluateInGlobalScope() { //void evaluate(QString expr, int frame = -1); - init(true); + QCOMPARE(init(true), ConnectSuccess); - client->connect(); + m_client->connect(); - do { + for (int i = 0; i < 10; ++i) { // The engine might not be initialized, yet. We just try until it shows up. - client->evaluate(QLatin1String("console.log('Hello World')")); - } while (!QQmlDebugTest::waitForSignal(client, SIGNAL(result()), 500)); + m_client->evaluate(QLatin1String("console.log('Hello World')")); + if (QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()), 500)) + break; + } //Verify the return value of 'console.log()', which is "undefined" - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); - QVariantMap body = value.value("body").toMap(); - QCOMPARE(body.value("type").toString(),QLatin1String("undefined")); + QCOMPARE(responseBody(m_client).value("type").toString(), QLatin1String("undefined")); } void tst_QQmlDebugJS::evaluateInLocalScope() @@ -1425,29 +1353,29 @@ void tst_QQmlDebugJS::evaluateInLocalScope() QFETCH(bool, redundantRefs); QFETCH(bool, namesAsObjects); int sourceLine = 34; - init(qmlscene, ONCOMPLETED_QMLFILE); + QCOMPARE(init(qmlscene, ONCOMPLETED_QMLFILE), ConnectSuccess); - client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QLatin1String(ONCOMPLETED_QMLFILE), sourceLine, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - client->frame(); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + m_client->frame(); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); //Get the frame index - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QVariantMap body = value.value("body").toMap(); int frameIndex = body.value("index").toInt(); - client->evaluate(QLatin1String("root.a"), frameIndex); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); + m_client->evaluate(QLatin1String("root.a"), frameIndex); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); //Verify the value of 'timer.interval' - jsonString = client->response; - value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + jsonString = m_client->response; + value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); body = value.value("body").toMap(); @@ -1456,25 +1384,25 @@ void tst_QQmlDebugJS::evaluateInLocalScope() void tst_QQmlDebugJS::evaluateInContext() { - connection = new QQmlDebugConnection(); - process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + m_connection = new QQmlDebugConnection(); + m_process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this); - client = new QJSDebugClient(connection); - QScopedPointer<QQmlEngineDebugClient> engineClient(new QQmlEngineDebugClient(connection)); - process->start(QStringList() << QLatin1String(BLOCKMODE) << testFile(ONCOMPLETED_QMLFILE)); + m_client = new QJSDebugClient(m_connection); + QScopedPointer<QQmlEngineDebugClient> engineClient(new QQmlEngineDebugClient(m_connection)); + m_process->start(QStringList() << QLatin1String(BLOCKMODE) << testFile(ONCOMPLETED_QMLFILE)); - QVERIFY(process->waitForSessionStart()); + QVERIFY(m_process->waitForSessionStart()); - connection->connectToHost("127.0.0.1", process->debugPort()); - QVERIFY(connection->waitForConnected()); + m_connection->connectToHost("127.0.0.1", m_process->debugPort()); + QVERIFY(m_connection->waitForConnected()); - QTRY_COMPARE(client->state(), QQmlEngineDebugClient::Enabled); + QTRY_COMPARE(m_client->state(), QQmlEngineDebugClient::Enabled); QTRY_COMPARE(engineClient->state(), QQmlEngineDebugClient::Enabled); - client->connect(); + m_client->connect(); // "a" not accessible without extra context - client->evaluate(QLatin1String("a + 10"), -1, -1); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(failure()))); + m_client->evaluate(QLatin1String("a + 10"), -1, -1); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(failure()))); bool success = false; engineClient->queryAvailableEngines(&success); @@ -1496,14 +1424,10 @@ void tst_QQmlDebugJS::evaluateInContext() auto object = engineClient->object(); // "a" accessible in context of surrounding object - client->evaluate(QLatin1String("a + 10"), -1, object.debugId); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); - - QString jsonString = client->response; - QVariantMap value = client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); + m_client->evaluate(QLatin1String("a + 10"), -1, object.debugId); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); - QVariantMap body = value.value("body").toMap(); - QTRY_COMPARE(body.value("value").toInt(), 20); + QTRY_COMPARE(responseBody(m_client).value("value").toInt(), 20); } void tst_QQmlDebugJS::getScripts() @@ -1513,16 +1437,16 @@ void tst_QQmlDebugJS::getScripts() QFETCH(bool, qmlscene); QFETCH(bool, redundantRefs); QFETCH(bool, namesAsObjects); - init(qmlscene); + QCOMPARE(init(qmlscene), ConnectSuccess); - client->setBreakpoint(QString(TEST_QMLFILE), 35, -1, true); - client->connect(redundantRefs, namesAsObjects); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(stopped()))); + m_client->setBreakpoint(QString(TEST_QMLFILE), 35, -1, true); + m_client->connect(redundantRefs, namesAsObjects); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(stopped()))); - client->scripts(); - QVERIFY(QQmlDebugTest::waitForSignal(client, SIGNAL(result()))); - QString jsonString(client->response); - QVariantMap value = client->parser.call(QJSValueList() + m_client->scripts(); + QVERIFY(QQmlDebugTest::waitForSignal(m_client, SIGNAL(result()))); + QString jsonString(m_client->response); + QVariantMap value = m_client->parser.call(QJSValueList() << QJSValue(jsonString)).toVariant().toMap(); QList<QVariant> scripts = value.value("body").toList(); @@ -1531,6 +1455,12 @@ void tst_QQmlDebugJS::getScripts() QVERIFY(scripts.first().toMap()[QStringLiteral("name")].toString().endsWith(QStringLiteral("data/test.qml"))); } +QList<QQmlDebugClient *> tst_QQmlDebugJS::createClients() +{ + m_client = new QJSDebugClient(m_connection); + return QList<QQmlDebugClient *>({m_client}); +} + void tst_QQmlDebugJS::targetData() { QTest::addColumn<bool>("qmlscene"); diff --git a/tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro b/tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro index 860d39cca4..1dc9de8f34 100644 --- a/tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro +++ b/tests/auto/qml/debugger/qqmldebuglocal/qqmldebuglocal.pro @@ -7,7 +7,6 @@ HEADERS += ../shared/qqmldebugtestservice.h SOURCES += tst_qqmldebuglocal.cpp \ ../shared/qqmldebugtestservice.cpp -INCLUDEPATH += ../shared include(../shared/debugutil.pri) QT += qml-private testlib gui-private core-private diff --git a/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp b/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp index 8d21a8a45a..4b28857fc0 100644 --- a/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp +++ b/tests/auto/qml/debugger/qqmldebuglocal/tst_qqmldebuglocal.cpp @@ -32,6 +32,9 @@ #include <private/qqmldebugconnector_p.h> #include <private/qqmldebugconnection_p.h> +#include <QtQml/qqmldebug.h> +#include <QtQml/qqmlengine.h> + #include <QtTest/qtest.h> #include <QtTest/qsignalspy.h> #include <QtNetwork/qhostaddress.h> diff --git a/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess.pro b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess.pro new file mode 100644 index 0000000000..331d87b9f1 --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess.pro @@ -0,0 +1,4 @@ +TEMPLATE = subdirs +SUBDIRS = qqmldebugprocess qqmldebugprocessprocess + +qqmldebugprocess.depends = qqmldebugprocessprocess diff --git a/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/qqmldebugprocess.pro b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/qqmldebugprocess.pro new file mode 100644 index 0000000000..9bea2d222c --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/qqmldebugprocess.pro @@ -0,0 +1,14 @@ +CONFIG += testcase +TARGET = tst_qqmldebugprocess +QT = core testlib +CONFIG -= debug_and_release_target +macos:CONFIG -= app_bundle + +SOURCES += \ + ../../shared/qqmldebugprocess.cpp \ + tst_qqmldebugprocess.cpp + +HEADERS += \ + ../../shared/qqmldebugprocess_p.h + +INCLUDEPATH += ../../shared diff --git a/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp new file mode 100644 index 0000000000..993a1d5f63 --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocess/tst_qqmldebugprocess.cpp @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 <qqmldebugprocess_p.h> +#include <QtTest> + +#include <QtCore/qcoreapplication.h> +#include <QtCore/qscopedpointer.h> + +class tst_QQmlDebugProcess : public QObject +{ + Q_OBJECT + +private slots: + void sessionStart_data(); + void sessionStart(); +}; + +void tst_QQmlDebugProcess::sessionStart_data() +{ + QTest::addColumn<int>("delay"); + QTest::addColumn<QString>("arg"); + QTest::addColumn<bool>("sessionExpected"); + QTest::addColumn<bool>("outputExpected"); + + QTest::addRow("synchronous / waiting") << -1 + << "QML Debugger: Waiting for connection on port 2423..." + << true << false; + QTest::addRow("synchronous / failed") << -1 << "QML Debugger: Unable to listen to port 242." + << false << false; + QTest::addRow("synchronous / unknown") << -1 << "QML Debugger: You don't know this string." + << false << true; + QTest::addRow("synchronous / appout") << -1 << "Output from app itself." + << false << true; + + QTest::addRow("no delay / waiting") << 0 + << "QML Debugger: Waiting for connection on port 2423..." + << true << false; + QTest::addRow("no delay / failed") << 0 << "QML Debugger: Unable to listen to port 242." + << false << false; + QTest::addRow("no delay / unknown") << 0 << "QML Debugger: You don't know this string." + << false << true; + QTest::addRow("no delay / appout") << 0 << "Output from app itself." + << false << true; + + QTest::addRow("delay / waiting") << 1000 + << "QML Debugger: Waiting for connection on port 2423..." + << true << false; + QTest::addRow("delay / failed") << 1000 << "QML Debugger: Unable to listen to port 242." + << false << false; + QTest::addRow("delay / unknown") << 1000 << "QML Debugger: You don't know this string." + << false << true; + QTest::addRow("delay / appout") << 1000 << "Output from app itself." + << false << true; +} + +void tst_QQmlDebugProcess::sessionStart() +{ + QFETCH(int, delay); + QFETCH(QString, arg); + QFETCH(bool, sessionExpected); + QFETCH(bool, outputExpected); + + QScopedPointer<QQmlDebugProcess> process( + new QQmlDebugProcess(QCoreApplication::applicationDirPath() + + QLatin1String("/qqmldebugprocessprocess"), this)); + QVERIFY(process); + + bool outputReceived = false; + connect(process.data(), &QQmlDebugProcess::readyReadStandardOutput, this, [&]() { + QVERIFY(outputExpected); + QVERIFY(!outputReceived); + QCOMPARE(process->output().trimmed(), arg); + outputReceived = true; + QTimer::singleShot(qMax(delay, 0), process.data(), &QQmlDebugProcess::stop); + }); + + if (!outputExpected && !sessionExpected) + QTest::ignoreMessage(QtWarningMsg, "App was unable to bind to port!"); + process->start(QStringList({arg})); + + bool done = false; + auto wait = [&](){ + QCOMPARE(process->waitForSessionStart(), sessionExpected); + QCOMPARE(outputReceived, outputExpected); + process->stop(); + done = true; + }; + + if (delay < 0) + wait(); + else + QTimer::singleShot(delay, process.data(), wait); + + QTRY_VERIFY(done); + QVERIFY(process->state().startsWith("not running")); +} + +QTEST_MAIN(tst_QQmlDebugProcess) + +#include "tst_qqmldebugprocess.moc" diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.cpp index fe01507412..21cce53fc3 100644 --- a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/plugin.cpp +++ b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the test suite of the Qt Toolkit. @@ -25,32 +25,15 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include <QStringList> -#include <QtQml/qqmlextensionplugin.h> -#include <QtQml/qqml.h> -#include <QDebug> - -class MyPluginType : public QObject -{ - Q_OBJECT -public: - MyPluginType(QObject *parent=0) : QObject(parent) {} -}; +#include <QtCore/qdebug.h> +#include <QtCore/qcoreapplication.h> -class MyPlugin : public QQmlExtensionPlugin +// Process that just outputs a fake "Waiting" message. +int main(int argc, char **argv) { - Q_OBJECT - Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) - -public: - MyPlugin() {} - - void registerTypes(const char *uri) - { - Q_ASSERT(QLatin1String(uri) == "org.qtproject.InvalidStrictModule"); - qmlRegisterType<MyPluginType>("org.qtproject.SomeOtherModule", 1, 0, "MyPluginType"); - } -}; - -#include "plugin.moc" + QCoreApplication app(argc, argv); + if (argc > 1) + qDebug() << argv[1]; + return app.exec(); +} diff --git a/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.pro b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.pro new file mode 100644 index 0000000000..a8eb4885d4 --- /dev/null +++ b/tests/auto/qml/debugger/qqmldebugprocess/qqmldebugprocessprocess/qqmldebugprocessprocess.pro @@ -0,0 +1,11 @@ +QT = core +macos:CONFIG -= app_bundle +CONFIG -= debug_and_release_target +CONFIG += console +SOURCES += qqmldebugprocessprocess.cpp + +DESTDIR = ../qqmldebugprocess + +target.path = $$[QT_INSTALL_TESTS]/tst_qqmldebugprocess +INSTALLS += target + diff --git a/tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro b/tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro index 79cbe52331..3101d09ea5 100644 --- a/tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro +++ b/tests/auto/qml/debugger/qqmldebugservice/qqmldebugservice.pro @@ -7,8 +7,6 @@ HEADERS += ../shared/qqmldebugtestservice.h SOURCES += tst_qqmldebugservice.cpp \ ../shared/qqmldebugtestservice.cpp -INCLUDEPATH += ../shared -include(../../../shared/util.pri) include(../shared/debugutil.pri) TESTDATA = data/* diff --git a/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp index 8092faba04..4e103e9a65 100644 --- a/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp +++ b/tests/auto/qml/debugger/qqmldebugservice/tst_qqmldebugservice.cpp @@ -29,6 +29,7 @@ #include "qqmldebugtestservice.h" #include "debugutil_p.h" +#include "qqmldebugprocess_p.h" #include "../../../shared/util.h" #include <private/qqmldebugclient_p.h> @@ -105,10 +106,13 @@ void tst_QQmlDebugService::initTestCase() void tst_QQmlDebugService::checkPortRange() { - QQmlDebugConnection *connection1 = new QQmlDebugConnection(); - QQmlDebugProcess *process1 = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this); + QScopedPointer<QQmlDebugConnection> connection1(new QQmlDebugConnection()); + QScopedPointer<QQmlDebugProcess> process1( + new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + + "/qmlscene", this)); - process1->start(QStringList() << QLatin1String("-qmljsdebugger=port:3782,3792") << testFile("test.qml")); + process1->start(QStringList() << QLatin1String("-qmljsdebugger=port:3782,3792") + << testFile("test.qml")); if (!process1->waitForSessionStart()) QFAIL("could not launch application, or did not get 'Waiting for connection'."); @@ -119,10 +123,13 @@ void tst_QQmlDebugService::checkPortRange() QFAIL("could not connect to host!"); // Second instance - QQmlDebugConnection *connection2 = new QQmlDebugConnection(); - QQmlDebugProcess *process2 = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", this); + QScopedPointer<QQmlDebugConnection> connection2(new QQmlDebugConnection()); + QScopedPointer<QQmlDebugProcess> process2( + new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + + "/qmlscene", this)); - process2->start(QStringList() << QLatin1String("-qmljsdebugger=port:3782,3792") << testFile("test.qml")); + process2->start(QStringList() << QLatin1String("-qmljsdebugger=port:3782,3792") + << testFile("test.qml")); if (!process2->waitForSessionStart()) QFAIL("could not launch application, or did not get 'Waiting for connection'."); @@ -131,11 +138,6 @@ void tst_QQmlDebugService::checkPortRange() connection2->connectToHost("127.0.0.1", port2); if (!connection2->waitForConnected()) QFAIL("could not connect to host!"); - - delete connection1; - delete process1; - delete connection2; - delete process2; } void tst_QQmlDebugService::name() diff --git a/tests/auto/qml/debugger/qqmlenginecontrol/qqmlenginecontrol.pro b/tests/auto/qml/debugger/qqmlenginecontrol/qqmlenginecontrol.pro index 40ec1230d6..73455bd903 100644 --- a/tests/auto/qml/debugger/qqmlenginecontrol/qqmlenginecontrol.pro +++ b/tests/auto/qml/debugger/qqmlenginecontrol/qqmlenginecontrol.pro @@ -4,13 +4,11 @@ osx:CONFIG -= app_bundle SOURCES += tst_qqmlenginecontrol.cpp -INCLUDEPATH += ../shared -include(../../../shared/util.pri) include(../shared/debugutil.pri) TESTDATA = data/* -QT += core qml testlib testlib-private gui-private core-private +QT += core qml testlib gui-private core-private OTHER_FILES += \ data/test.qml \ diff --git a/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp b/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp index 2c515d7cf5..a8c43b1c75 100644 --- a/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp +++ b/tests/auto/qml/debugger/qqmlenginecontrol/tst_qqmlenginecontrol.cpp @@ -35,12 +35,8 @@ #include <private/qqmlenginecontrolclient_p.h> #include <QtTest/qtest.h> -#include <private/qtestresult_p.h> #include <QtCore/qlibraryinfo.h> -#define STR_PORT_FROM "13773" -#define STR_PORT_TO "13783" - class QQmlEngineBlocker : public QObject { Q_OBJECT @@ -65,77 +61,37 @@ void QQmlEngineBlocker::blockEngine(int engineId, const QString &name) static_cast<QQmlEngineControlClient *>(parent())->blockEngine(engineId); } -class tst_QQmlEngineControl : public QQmlDataTest +class tst_QQmlEngineControl : public QQmlDebugTest { Q_OBJECT -public: - tst_QQmlEngineControl() - : m_process(0) - , m_connection(0) - , m_client(0) - {} - private: - QQmlDebugProcess *m_process; - QQmlDebugConnection *m_connection; - QQmlEngineControlClient *m_client; + ConnectResult connect(const QString &testFile, bool restrictServices); + QList<QQmlDebugClient *> createClients() override; - void connect(const QString &testFile, bool restrictServices); void engine_data(); + QPointer<QQmlEngineControlClient> m_client; private slots: - void cleanup(); - void startEngine_data(); void startEngine(); void stopEngine_data(); void stopEngine(); }; -void tst_QQmlEngineControl::connect(const QString &testFile, bool restrictServices) +QQmlDebugTest::ConnectResult tst_QQmlEngineControl::connect(const QString &file, + bool restrictServices) { - const QString executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene"; - QStringList arguments; - arguments << QString::fromLatin1("-qmljsdebugger=port:%1,%2,block%3") - .arg(STR_PORT_FROM).arg(STR_PORT_TO) - .arg(restrictServices ? QStringLiteral(",services:EngineControl") : QString()); - - arguments << QQmlDataTest::instance()->testFile(testFile); - - m_process = new QQmlDebugProcess(executable, this); - m_process->start(QStringList() << arguments); - QVERIFY2(m_process->waitForSessionStart(), "Could not launch application, or did not get 'Waiting for connection'."); - - m_connection = new QQmlDebugConnection(); - m_client = new QQmlEngineControlClient(m_connection); - new QQmlEngineBlocker(m_client); - QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(m_connection); - - const int port = m_process->debugPort(); - m_connection->connectToHost(QLatin1String("127.0.0.1"), port); - - QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); - foreach (QQmlDebugClient *other, others) - QCOMPARE(other->state(), restrictServices ? QQmlDebugClient::Unavailable : - QQmlDebugClient::Enabled); - qDeleteAll(others); + return QQmlDebugTest::connect(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", + restrictServices ? QStringLiteral("EngineControl") : QString(), + testFile(file), true); } -void tst_QQmlEngineControl::cleanup() +QList<QQmlDebugClient *> tst_QQmlEngineControl::createClients() { - if (QTest::currentTestFailed()) { - qDebug() << "Process State:" << (m_process ? m_process->state() : QLatin1String("null")); - qDebug() << "Application Output:" << (m_process ? m_process->output() : QLatin1String("null")); - qDebug() << "Connection State:" << QQmlDebugTest::connectionStateString(m_connection); - qDebug() << "Client State:" << QQmlDebugTest::clientStateString(m_client); - } - delete m_process; - m_process = 0; - delete m_client; - m_client = 0; - delete m_connection; - m_connection = 0; + m_client = new QQmlEngineControlClient(m_connection); + new QQmlEngineBlocker(m_client); + return QList<QQmlDebugClient *>({m_client}); } void tst_QQmlEngineControl::engine_data() @@ -153,16 +109,16 @@ void tst_QQmlEngineControl::startEngine_data() void tst_QQmlEngineControl::startEngine() { QFETCH(bool, restrictMode); - - connect("test.qml", restrictMode); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; + QCOMPARE(connect("test.qml", restrictMode), ConnectSuccess); QTRY_VERIFY(!m_client->blockedEngines().empty()); m_client->releaseEngine(m_client->blockedEngines().last()); + QVERIFY(m_client->blockedEngines().isEmpty()); QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(engineAdded(int,QString))), "No engine start message received in time."); + + QVERIFY(m_client->blockedEngines().isEmpty()); } void tst_QQmlEngineControl::stopEngine_data() @@ -174,21 +130,23 @@ void tst_QQmlEngineControl::stopEngine() { QFETCH(bool, restrictMode); - connect("exit.qml", restrictMode); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; + QCOMPARE(connect("exit.qml", restrictMode), ConnectSuccess); QTRY_VERIFY(!m_client->blockedEngines().empty()); m_client->releaseEngine(m_client->blockedEngines().last()); + QVERIFY(m_client->blockedEngines().isEmpty()); QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(engineAdded(int,QString))), "No engine start message received in time."); + QVERIFY(m_client->blockedEngines().isEmpty()); QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(engineAboutToBeRemoved(int,QString))), "No engine about to stop message received in time."); m_client->releaseEngine(m_client->blockedEngines().last()); + QVERIFY(m_client->blockedEngines().isEmpty()); QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(engineRemoved(int,QString))), "No engine stop message received in time."); + QVERIFY(m_client->blockedEngines().isEmpty()); } QTEST_MAIN(tst_QQmlEngineControl) diff --git a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/qqmlenginedebuginspectorintegrationtest.pro b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/qqmlenginedebuginspectorintegrationtest.pro index b8b4c3fc8b..5f58e5ec7f 100644 --- a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/qqmlenginedebuginspectorintegrationtest.pro +++ b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/qqmlenginedebuginspectorintegrationtest.pro @@ -1,13 +1,11 @@ CONFIG += testcase TARGET = tst_qqmlenginedebuginspectorintegration -QT += qml testlib testlib-private gui-private core-private +QT += qml testlib gui-private core-private osx:CONFIG -= app_bundle SOURCES += tst_qqmlenginedebuginspectorintegration.cpp -INCLUDEPATH += ../shared -include(../../../shared/util.pri) include(../shared/qqmlinspectorclient.pri) include(../shared/qqmlenginedebugclient.pri) include(../shared/debugutil.pri) diff --git a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp index aba9eb39ab..249416a3b9 100644 --- a/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp +++ b/tests/auto/qml/debugger/qqmlenginedebuginspectorintegrationtest/tst_qqmlenginedebuginspectorintegration.cpp @@ -34,7 +34,6 @@ #include <private/qqmldebugconnection_p.h> #include <QtTest/qtest.h> -#include <private/qtestresult_p.h> #include <QtTest/qsignalspy.h> #include <QtNetwork/qhostaddress.h> #include <QtCore/qtimer.h> @@ -42,35 +41,21 @@ #include <QtCore/qthread.h> #include <QtCore/qlibraryinfo.h> -#define STR_PORT_FROM "3776" -#define STR_PORT_TO "3786" - -class tst_QQmlEngineDebugInspectorIntegration : public QQmlDataTest +class tst_QQmlEngineDebugInspectorIntegration : public QQmlDebugTest { Q_OBJECT -public: - tst_QQmlEngineDebugInspectorIntegration() - : m_process(0) - , m_inspectorClient(0) - , m_engineDebugClient(0) - , m_recipient(0) - { - } - - private: - void init(bool restrictServices); + ConnectResult init(bool restrictServices); + QList<QQmlDebugClient *> createClients() override; + QmlDebugObjectReference findRootObject(); - QQmlDebugProcess *m_process; - QQmlInspectorClient *m_inspectorClient; - QQmlEngineDebugClient *m_engineDebugClient; - QQmlInspectorResultRecipient *m_recipient; + QPointer<QQmlInspectorClient> m_inspectorClient; + QPointer<QQmlEngineDebugClient> m_engineDebugClient; + QPointer<QQmlInspectorResultRecipient> m_recipient; private slots: - void cleanup(); - void connect_data(); void connect(); void objectLocationLookup(); @@ -100,53 +85,22 @@ QmlDebugObjectReference tst_QQmlEngineDebugInspectorIntegration::findRootObject( return m_engineDebugClient->object(); } -void tst_QQmlEngineDebugInspectorIntegration::init(bool restrictServices) +QQmlDebugTest::ConnectResult tst_QQmlEngineDebugInspectorIntegration::init(bool restrictServices) { - const QString argument = QString::fromLatin1("-qmljsdebugger=port:%1,%2,block%3") - .arg(STR_PORT_FROM).arg(STR_PORT_TO) - .arg(restrictServices ? QStringLiteral(",services:QmlDebugger,QmlInspector") : - QString()); - - m_process = new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml", - this); - m_process->start(QStringList() << argument << testFile("qtquick2.qml")); - QVERIFY2(m_process->waitForSessionStart(), - "Could not launch application, or did not get 'Waiting for connection'."); - - QQmlDebugConnection *m_connection = new QQmlDebugConnection(this); - m_inspectorClient = new QQmlInspectorClient(m_connection); - m_engineDebugClient = new QQmlEngineDebugClient(m_connection); - m_recipient = new QQmlInspectorResultRecipient(this); - QObject::connect(m_inspectorClient, &QQmlInspectorClient::responseReceived, - m_recipient, &QQmlInspectorResultRecipient::recordResponse); - - QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(m_connection); - - m_connection->connectToHost(QLatin1String("127.0.0.1"), m_process->debugPort()); - QVERIFY(m_connection->waitForConnected()); - foreach (QQmlDebugClient *other, others) - QCOMPARE(other->state(), restrictServices ? QQmlDebugClient::Unavailable : - QQmlDebugClient::Enabled); - qDeleteAll(others); - - QTRY_COMPARE(m_inspectorClient->state(), QQmlDebugClient::Enabled); - QTRY_COMPARE(m_engineDebugClient->state(), QQmlDebugClient::Enabled); + return QQmlDebugTest::connect( + QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml", + restrictServices ? QStringLiteral("QmlDebugger,QmlInspector") : QString(), + testFile("qtquick2.qml"), true); } -void tst_QQmlEngineDebugInspectorIntegration::cleanup() +QList<QQmlDebugClient *> tst_QQmlEngineDebugInspectorIntegration::createClients() { - if (QTest::currentTestFailed()) { - qDebug() << "Process State:" << m_process->state(); - qDebug() << "Application Output:" << m_process->output(); - } - delete m_process; - m_process = 0; - delete m_engineDebugClient; - m_engineDebugClient = 0; - delete m_inspectorClient; - m_inspectorClient = 0; - delete m_recipient; - m_recipient = 0; + m_inspectorClient = new QQmlInspectorClient(m_connection); + m_engineDebugClient = new QQmlEngineDebugClient(m_connection); + m_recipient = new QQmlInspectorResultRecipient(m_inspectorClient); + QObject::connect(m_inspectorClient.data(), &QQmlInspectorClient::responseReceived, + m_recipient.data(), &QQmlInspectorResultRecipient::recordResponse); + return QList<QQmlDebugClient *>({m_inspectorClient, m_engineDebugClient}); } void tst_QQmlEngineDebugInspectorIntegration::connect_data() @@ -159,14 +113,12 @@ void tst_QQmlEngineDebugInspectorIntegration::connect_data() void tst_QQmlEngineDebugInspectorIntegration::connect() { QFETCH(bool, restrictMode); - init(restrictMode); + QCOMPARE(init(restrictMode), ConnectSuccess); } void tst_QQmlEngineDebugInspectorIntegration::objectLocationLookup() { - init(true); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; + QCOMPARE(init(true), ConnectSuccess); bool success = false; QmlDebugObjectReference rootObject = findRootObject(); @@ -192,9 +144,7 @@ void tst_QQmlEngineDebugInspectorIntegration::objectLocationLookup() void tst_QQmlEngineDebugInspectorIntegration::select() { - init(true); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; + QCOMPARE(init(true), ConnectSuccess); QmlDebugObjectReference rootObject = findRootObject(); QList<int> childIds; @@ -212,9 +162,7 @@ void tst_QQmlEngineDebugInspectorIntegration::select() void tst_QQmlEngineDebugInspectorIntegration::createObject() { - init(true); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; + QCOMPARE(init(true), ConnectSuccess); QString qml = QLatin1String("Rectangle {\n" " id: xxxyxxx\n" @@ -241,9 +189,7 @@ void tst_QQmlEngineDebugInspectorIntegration::createObject() void tst_QQmlEngineDebugInspectorIntegration::moveObject() { - init(true); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; + QCOMPARE(init(true), ConnectSuccess); QCOMPARE(m_inspectorClient->state(), QQmlDebugClient::Enabled); QmlDebugObjectReference rootObject = findRootObject(); @@ -268,9 +214,7 @@ void tst_QQmlEngineDebugInspectorIntegration::moveObject() void tst_QQmlEngineDebugInspectorIntegration::destroyObject() { - init(true); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; + QCOMPARE(init(true), ConnectSuccess); QCOMPARE(m_inspectorClient->state(), QQmlDebugClient::Enabled); QmlDebugObjectReference rootObject = findRootObject(); diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/qqmlenginedebugservice.pro b/tests/auto/qml/debugger/qqmlenginedebugservice/qqmlenginedebugservice.pro index 06250d9940..33ee023c06 100644 --- a/tests/auto/qml/debugger/qqmlenginedebugservice/qqmlenginedebugservice.pro +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/qqmlenginedebugservice.pro @@ -5,8 +5,6 @@ osx:CONFIG -= app_bundle SOURCES += \ tst_qqmlenginedebugservice.cpp -INCLUDEPATH += ../shared -include(../../../shared/util.pri) include(../shared/qqmlenginedebugclient.pri) include(../shared/debugutil.pri) diff --git a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp index 6d31ff9219..8993ce7cf4 100644 --- a/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp +++ b/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp @@ -229,9 +229,23 @@ void tst_QQmlEngineDebugService::recursiveObjectTest( QCOMPARE(p.name, QString::fromUtf8(pmeta.name())); - if (pmeta.type() < QVariant::UserType && pmeta.userType() != - QMetaType::QVariant) // TODO test complex types - QCOMPARE(p.value , pmeta.read(o)); + if (pmeta.userType() == QMetaType::QObjectStar) { + const QmlDebugObjectReference ref = qvariant_cast<QmlDebugObjectReference>(p.value); + QObject *pobj = qvariant_cast<QObject *>(pmeta.read(o)); + if (pobj) { + if (pobj->objectName().isEmpty()) + QCOMPARE(ref.name, QString("<unnamed object>")); + else + QCOMPARE(ref.name, pobj->objectName()); + } else { + QCOMPARE(ref.name, QString("<unknown value>")); + } + } else if (pmeta.type() < QVariant::UserType && pmeta.userType() != QMetaType::QVariant) { + const QVariant expected = pmeta.read(o); + QVERIFY2(p.value == expected, QString::fromLatin1("%1 != %2. Details: %3/%4/%5/%6") + .arg(QTest::toString(p.value)).arg(QTest::toString(expected)).arg(p.name) + .arg(p.valueTypeName).arg(pmeta.type()).arg(pmeta.userType()).toUtf8()); + } if (p.name == "parent") QVERIFY(p.valueTypeName == "QGraphicsObject*" || @@ -1259,7 +1273,8 @@ void tst_QQmlEngineDebugService::queryObjectTree() QmlDebugObjectReference targetReference = qvariant_cast<QmlDebugObjectReference>(propertyChangeTarget.value); QVERIFY(!targetReference.className.isEmpty()); - QVERIFY(targetReference.debugId != -1); + QCOMPARE(targetReference.debugId, -1); + QCOMPARE(targetReference.name, QString("<unnamed object>")); // check transition QmlDebugObjectReference transition = obj.children[0]; @@ -1277,7 +1292,8 @@ void tst_QQmlEngineDebugService::queryObjectTree() targetReference = qvariant_cast<QmlDebugObjectReference>(animationTarget.value); QVERIFY(!targetReference.className.isEmpty()); - QVERIFY(targetReference.debugId != -1); + QCOMPARE(targetReference.debugId, -1); + QCOMPARE(targetReference.name, QString("<unnamed object>")); QCOMPARE(findProperty(animation.properties,"property").value.toString(), QString("width")); QCOMPARE(findProperty(animation.properties,"duration").value.toInt(), 100); diff --git a/tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro b/tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro index ee5f3c708a..fd07255ae5 100644 --- a/tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro +++ b/tests/auto/qml/debugger/qqmlinspector/qqmlinspector.pro @@ -6,8 +6,6 @@ osx:CONFIG -= app_bundle SOURCES += tst_qqmlinspector.cpp -INCLUDEPATH += ../shared -include(../../../shared/util.pri) include(../shared/qqmlinspectorclient.pri) include(../shared/debugutil.pri) diff --git a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp index 9461922eff..5c9506eb21 100644 --- a/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp +++ b/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp @@ -28,6 +28,7 @@ #include "qqmlinspectorclient.h" #include "../shared/debugutil_p.h" +#include "../shared/qqmldebugprocess_p.h" #include "../../../shared/util.h" #include <private/qqmldebugconnection_p.h> @@ -40,64 +41,32 @@ #include <QtCore/qlibraryinfo.h> #include <QtNetwork/qhostaddress.h> -#define STR_PORT_FROM "3772" -#define STR_PORT_TO "3782" - - -class tst_QQmlInspector : public QQmlDataTest +class tst_QQmlInspector : public QQmlDebugTest { Q_OBJECT private: - void startQmlProcess(const QString &qmlFile, bool restrictMode = true); + ConnectResult startQmlProcess(const QString &qmlFile, bool restrictMode = true); void checkAnimationSpeed(int targetMillisPerDegree); + QList<QQmlDebugClient *> createClients() override; + QQmlDebugProcess *createProcess(const QString &executable) override; -private: - QScopedPointer<QQmlDebugProcess> m_process; - QScopedPointer<QQmlDebugConnection> m_connection; - QScopedPointer<QQmlInspectorClient> m_client; - QScopedPointer<QQmlInspectorResultRecipient> m_recipient; + QPointer<QQmlInspectorClient> m_client; + QPointer<QQmlInspectorResultRecipient> m_recipient; private slots: - void cleanup(); - void connect_data(); void connect(); void setAnimationSpeed(); void showAppOnTop(); }; -void tst_QQmlInspector::startQmlProcess(const QString &qmlFile, bool restrictServices) +QQmlDebugTest::ConnectResult tst_QQmlInspector::startQmlProcess(const QString &qmlFile, + bool restrictServices) { - const QString argument = QString::fromLatin1("-qmljsdebugger=port:%1,%2,block%3") - .arg(STR_PORT_FROM).arg(STR_PORT_TO) - .arg(restrictServices ? QStringLiteral(",services:QmlInspector") : QString()); - - m_process.reset(new QQmlDebugProcess(QLibraryInfo::location(QLibraryInfo::BinariesPath) + - "/qml")); - // Make sure the animation timing is exact - m_process->addEnvironment(QLatin1String("QSG_RENDER_LOOP=basic")); - m_process->start(QStringList() << argument << testFile(qmlFile)); - QVERIFY2(m_process->waitForSessionStart(), - "Could not launch application, or did not get 'Waiting for connection'."); - - m_client.reset(); - m_connection.reset(new QQmlDebugConnection); - m_client.reset(new QQmlInspectorClient(m_connection.data())); - - m_recipient.reset(new QQmlInspectorResultRecipient); - QObject::connect(m_client.data(), &QQmlInspectorClient::responseReceived, - m_recipient.data(), &QQmlInspectorResultRecipient::recordResponse); - - QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(m_connection.data()); - - m_connection->connectToHost(QLatin1String("127.0.0.1"), m_process->debugPort()); - QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); - - foreach (QQmlDebugClient *other, others) - QCOMPARE(other->state(), restrictServices ? QQmlDebugClient::Unavailable : - QQmlDebugClient::Enabled); - qDeleteAll(others); + return QQmlDebugTest::connect(QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml", + restrictServices ? QStringLiteral("QmlInspector") : QString(), + testFile(qmlFile), true); } void tst_QQmlInspector::checkAnimationSpeed(int targetMillisPerDegree) @@ -114,8 +83,7 @@ void tst_QQmlInspector::checkAnimationSpeed(int targetMillisPerDegree) QString output = m_process->output(); int position = output.length(); do { - QVERIFY(QQmlDebugTest::waitForSignal(m_process.data(), - SIGNAL(readyReadStandardOutput()))); + QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput()))); output = m_process->output(); } while (!output.mid(position).contains(markerString)); @@ -144,12 +112,21 @@ void tst_QQmlInspector::checkAnimationSpeed(int targetMillisPerDegree) .arg(targetMillisPerDegree).toLocal8Bit().constData()); } -void tst_QQmlInspector::cleanup() +QList<QQmlDebugClient *> tst_QQmlInspector::createClients() { - if (QTest::currentTestFailed()) { - qDebug() << "Process State:" << m_process->state(); - qDebug() << "Application Output:" << m_process->output(); - } + m_client = new QQmlInspectorClient(m_connection); + m_recipient = new QQmlInspectorResultRecipient(m_client); + QObject::connect(m_client.data(), &QQmlInspectorClient::responseReceived, + m_recipient.data(), &QQmlInspectorResultRecipient::recordResponse); + return QList<QQmlDebugClient *>({m_client}); +} + +QQmlDebugProcess *tst_QQmlInspector::createProcess(const QString &executable) +{ + QQmlDebugProcess *process = QQmlDebugTest::createProcess(executable); + // Make sure the animation timing is exact + process->addEnvironment(QLatin1String("QSG_RENDER_LOOP=basic")); + return process; } void tst_QQmlInspector::connect_data() @@ -166,7 +143,7 @@ void tst_QQmlInspector::connect() { QFETCH(QString, file); QFETCH(bool, restrictMode); - startQmlProcess(file, restrictMode); + QCOMPARE(startQmlProcess(file, restrictMode), ConnectSuccess); QVERIFY(m_client); QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); @@ -181,7 +158,7 @@ void tst_QQmlInspector::connect() void tst_QQmlInspector::showAppOnTop() { - startQmlProcess("qtquick2.qml"); + QCOMPARE(startQmlProcess("qtquick2.qml"), ConnectSuccess); QVERIFY(m_client); QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); @@ -196,7 +173,7 @@ void tst_QQmlInspector::showAppOnTop() void tst_QQmlInspector::setAnimationSpeed() { - startQmlProcess("qtquick2.qml"); + QCOMPARE(startQmlProcess("qtquick2.qml"), ConnectSuccess); QVERIFY(m_client); QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); checkAnimationSpeed(10); diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml index dd7cb2055d..4235a2d55f 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/controlFromJS.qml @@ -43,13 +43,6 @@ QtObject { interval: 1000 onTriggered: { console.profileEnd(); - endTimer.start(); } } - - property var endTimer: Timer { - id: endTimer - interval: 1000 - onTriggered: Qt.quit(); - } } diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml index 4236d70ea3..3b28e65174 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/exit.qml @@ -1,7 +1,7 @@ import QtQml 2.0 QtObject { - Timer { + property Timer timer: Timer { running: true interval: 1 onTriggered: Qt.quit(); diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/data/qstr.qml b/tests/auto/qml/debugger/qqmlprofilerservice/data/qstr.qml new file mode 100644 index 0000000000..09dcd34b5c --- /dev/null +++ b/tests/auto/qml/debugger/qqmlprofilerservice/data/qstr.qml @@ -0,0 +1,9 @@ +import QtQml 2.0 + +Timer { + property string stuff: qsTr("foo") + + running: true + interval: 1 + onTriggered: Qt.quit(); +} diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro index 56840d5c8f..7c78b5fcb3 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro +++ b/tests/auto/qml/debugger/qqmlprofilerservice/qqmlprofilerservice.pro @@ -4,8 +4,6 @@ osx:CONFIG -= app_bundle SOURCES += tst_qqmlprofilerservice.cpp -INCLUDEPATH += ../shared -include(../../../shared/util.pri) include(../shared/debugutil.pri) TESTDATA = data/* @@ -22,4 +20,5 @@ OTHER_FILES += \ data/signalSourceLocation.qml \ data/javascript.qml \ data/timer.qml \ + data/qstr.qml \ data/memory.qml diff --git a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp index bc6c51707a..db28d3202d 100644 --- a/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp +++ b/tests/auto/qml/debugger/qqmlprofilerservice/tst_qqmlprofilerservice.cpp @@ -27,6 +27,7 @@ ****************************************************************************/ #include "debugutil_p.h" +#include "qqmldebugprocess_p.h" #include "../../../shared/util.h" #include <private/qqmlprofilerclient_p.h> @@ -36,246 +37,144 @@ #include <private/qtestresult_p.h> #include <QtCore/qlibraryinfo.h> -#define STR_PORT_FROM "13773" -#define STR_PORT_TO "13783" +#include <QtGui/private/qguiapplication_p.h> +#include <QtGui/qpa/qplatformintegration.h> -struct QQmlProfilerData -{ - QQmlProfilerData(qint64 time = -2, int messageType = -1, int detailType = -1, - const QString &detailData = QString()) : - time(time), messageType(messageType), detailType(detailType), detailData(detailData), - line(-1), column(-1), framerate(-1), animationcount(-1), amount(-1) - {} - - qint64 time; - int messageType; - int detailType; - - //### - QString detailData; //used by RangeData and RangeLocation - int line; //used by RangeLocation - int column; //used by RangeLocation - int framerate; //used by animation events - int animationcount; //used by animation events - qint64 amount; //used by heap events -}; - -class QQmlProfilerTestClient : public QQmlProfilerClient +class QQmlProfilerTestClient : public QQmlProfilerEventReceiver, public QQmlProfilerDefinitions { Q_OBJECT public: - QQmlProfilerTestClient(QQmlDebugConnection *connection) : QQmlProfilerClient(connection), - lastTimestamp(-1) {} + QQmlProfilerTestClient(QQmlDebugConnection *connection) : + client(new QQmlProfilerClient(connection, this)) + { + connect(client.data(), &QQmlProfilerClient::traceStarted, + this, &QQmlProfilerTestClient::startTrace); + connect(client.data(), &QQmlProfilerClient::traceFinished, + this, &QQmlProfilerTestClient::endTrace); + } - QVector<QQmlProfilerData> qmlMessages; - QVector<QQmlProfilerData> javascriptMessages; - QVector<QQmlProfilerData> jsHeapMessages; - QVector<QQmlProfilerData> asynchronousMessages; - QVector<QQmlProfilerData> pixmapMessages; + void startTrace(qint64 timestamp, const QList<int> &engineIds); + void endTrace(qint64 timestamp, const QList<int> &engineIds); - qint64 lastTimestamp; + QPointer<QQmlProfilerClient> client; // Owned by QQmlDebugTest + QVector<QQmlProfilerEventType> types; -signals: - void recordingFinished(); + QVector<QQmlProfilerEvent> qmlMessages; + QVector<QQmlProfilerEvent> javascriptMessages; + QVector<QQmlProfilerEvent> jsHeapMessages; + QVector<QQmlProfilerEvent> asynchronousMessages; + QVector<QQmlProfilerEvent> pixmapMessages; -private: - void traceStarted(qint64 time, int engineId); - void traceFinished(qint64 time, int engineId); - void rangeStart(QQmlProfilerDefinitions::RangeType type, qint64 startTime); - void rangeData(QQmlProfilerDefinitions::RangeType type, qint64 time, const QString &data); - void rangeLocation(QQmlProfilerDefinitions::RangeType type, qint64 time, - const QQmlEventLocation &location); - void rangeEnd(QQmlProfilerDefinitions::RangeType type, qint64 endTime); - void animationFrame(qint64 time, int frameRate, int animationCount, int threadId); - void sceneGraphEvent(QQmlProfilerDefinitions::SceneGraphFrameType type, qint64 time, - qint64 numericData1, qint64 numericData2, qint64 numericData3, - qint64 numericData4, qint64 numericData5); - void pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEventType type, qint64 time, - const QString &url, int numericData1, int numericData2); - void memoryAllocation(QQmlProfilerDefinitions::MemoryType type, qint64 time, qint64 amount); - void inputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time, int a, int b); - void complete(); - - void unknownEvent(QQmlProfilerDefinitions::Message messageType, qint64 time, int detailType); - void unknownData(QPacket &stream); + int numLoadedEventTypes() const override; + void addEventType(const QQmlProfilerEventType &type) override; + void addEvent(const QQmlProfilerEvent &event) override; }; -void QQmlProfilerTestClient::traceStarted(qint64 time, int engineId) -{ - asynchronousMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::Event, - QQmlProfilerDefinitions::StartTrace, - QString::number(engineId))); -} - -void QQmlProfilerTestClient::traceFinished(qint64 time, int engineId) +void QQmlProfilerTestClient::startTrace(qint64 timestamp, const QList<int> &engineIds) { - asynchronousMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::Event, - QQmlProfilerDefinitions::EndTrace, - QString::number(engineId))); + types.append(QQmlProfilerEventType(Event, MaximumRangeType, StartTrace)); + asynchronousMessages.append(QQmlProfilerEvent(timestamp, types.length() - 1, + engineIds.toVector())); } -void QQmlProfilerTestClient::rangeStart(QQmlProfilerDefinitions::RangeType type, qint64 startTime) +void QQmlProfilerTestClient::endTrace(qint64 timestamp, const QList<int> &engineIds) { - QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); - QVERIFY(lastTimestamp <= startTime); - lastTimestamp = startTime; - QQmlProfilerData data(startTime, QQmlProfilerDefinitions::RangeStart, type); - if (type == QQmlProfilerDefinitions::Javascript) - javascriptMessages.append(data); - else - qmlMessages.append(data); + types.append(QQmlProfilerEventType(Event, MaximumRangeType, EndTrace)); + asynchronousMessages.append(QQmlProfilerEvent(timestamp, types.length() - 1, + engineIds.toVector())); } -void QQmlProfilerTestClient::rangeData(QQmlProfilerDefinitions::RangeType type, qint64 time, - const QString &string) +int QQmlProfilerTestClient::numLoadedEventTypes() const { - QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); - QVERIFY(lastTimestamp <= time); - lastTimestamp = time; - QQmlProfilerData data(time, QQmlProfilerDefinitions::RangeData, type, string); - if (type == QQmlProfilerDefinitions::Javascript) - javascriptMessages.append(data); - else - qmlMessages.append(data); + return types.length(); } -void QQmlProfilerTestClient::rangeLocation(QQmlProfilerDefinitions::RangeType type, qint64 time, - const QQmlEventLocation &location) +void QQmlProfilerTestClient::addEventType(const QQmlProfilerEventType &type) { - QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); - QVERIFY(location.line >= -2); - QVERIFY(lastTimestamp <= time); - lastTimestamp = time; - QQmlProfilerData data(time, QQmlProfilerDefinitions::RangeLocation, type, location.filename); - data.line = location.line; - data.column = location.column; - if (type == QQmlProfilerDefinitions::Javascript) - javascriptMessages.append(data); - else - qmlMessages.append(data); + types.append(type); } -void QQmlProfilerTestClient::rangeEnd(QQmlProfilerDefinitions::RangeType type, qint64 endTime) +void QQmlProfilerTestClient::addEvent(const QQmlProfilerEvent &event) { - QVERIFY(type >= 0 && type < QQmlProfilerDefinitions::MaximumRangeType); - QVERIFY(lastTimestamp <= endTime); - lastTimestamp = endTime; - QQmlProfilerData data(endTime, QQmlProfilerDefinitions::RangeEnd, type); - if (type == QQmlProfilerDefinitions::Javascript) - javascriptMessages.append(data); - else - qmlMessages.append(data); -} + const int typeIndex = event.typeIndex(); + QVERIFY(typeIndex < types.length()); -void QQmlProfilerTestClient::animationFrame(qint64 time, int frameRate, int animationCount, int threadId) -{ - QVERIFY(threadId >= 0); - QVERIFY(frameRate != -1); - QVERIFY(animationCount != -1); - QVERIFY(lastTimestamp <= time); - lastTimestamp = time; - QQmlProfilerData data(time, QQmlProfilerDefinitions::Event, - QQmlProfilerDefinitions::AnimationFrame); - data.framerate = frameRate; - data.animationcount = animationCount; - asynchronousMessages.append(data); -} - -void QQmlProfilerTestClient::sceneGraphEvent(QQmlProfilerDefinitions::SceneGraphFrameType type, - qint64 time, qint64 numericData1, qint64 numericData2, - qint64 numericData3, qint64 numericData4, - qint64 numericData5) -{ - Q_UNUSED(numericData1); - Q_UNUSED(numericData2); - Q_UNUSED(numericData3); - Q_UNUSED(numericData4); - Q_UNUSED(numericData5); - QVERIFY(lastTimestamp <= time); - lastTimestamp = time; - asynchronousMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::SceneGraphFrame, - type)); -} + const QQmlProfilerEventType &type = types[typeIndex]; -void QQmlProfilerTestClient::pixmapCacheEvent(QQmlProfilerDefinitions::PixmapEventType type, - qint64 time, const QString &url, int numericData1, - int numericData2) -{ - QVERIFY(lastTimestamp <= time); - lastTimestamp = time; - QQmlProfilerData data(time, QQmlProfilerDefinitions::PixmapCacheEvent, type, url); - switch (type) { - case QQmlProfilerDefinitions::PixmapSizeKnown: - data.line = numericData1; - data.column = numericData2; + switch (type.message()) { + case Event: { + switch (type.detailType()) { + case StartTrace: + QFAIL("StartTrace should not be passed on as event"); + break; + case EndTrace: + QFAIL("EndTrace should not be passed on as event"); + break; + case AnimationFrame: + asynchronousMessages.append(event); + break; + case Mouse: + case Key: + qmlMessages.append(event); + break; + default: + QFAIL(qPrintable(QString::fromLatin1("Event with unknown detailType %1 received at %2.") + .arg(type.detailType()).arg(event.timestamp()))); + break; + } + break; + } + case RangeStart: + case RangeData: + case RangeLocation: + case RangeEnd: + QFAIL("Range stages are transmitted as part of events"); + break; + case Complete: + QFAIL("Complete should not be passed on as event"); + break; + case PixmapCacheEvent: + pixmapMessages.append(event); + break; + case SceneGraphFrame: + asynchronousMessages.append(event); break; - case QQmlProfilerDefinitions::PixmapReferenceCountChanged: - case QQmlProfilerDefinitions::PixmapCacheCountChanged: - data.animationcount = numericData1; + case MemoryAllocation: + jsHeapMessages.append(event); break; - default: + case DebugMessage: + // Unhandled + break; + case MaximumMessage: + switch (type.rangeType()) { + case Painting: + QFAIL("QtQuick1 paint message received."); + break; + case Compiling: + case Creating: + case Binding: + case HandlingSignal: + qmlMessages.append(event); + break; + case Javascript: + javascriptMessages.append(event); + break; + default: + QFAIL(qPrintable( + QString::fromLatin1("Unknown range event %1 received at %2.") + .arg(type.rangeType()).arg(event.timestamp()))); + break; + } break; } - pixmapMessages.append(data); -} - -void QQmlProfilerTestClient::memoryAllocation(QQmlProfilerDefinitions::MemoryType type, qint64 time, - qint64 amount) -{ - QVERIFY(lastTimestamp <= time); - lastTimestamp = time; - QQmlProfilerData data(time, QQmlProfilerDefinitions::MemoryAllocation, type); - data.amount = amount; - jsHeapMessages.append(data); } -void QQmlProfilerTestClient::inputEvent(QQmlProfilerDefinitions::InputEventType type, qint64 time, - int a, int b) -{ - QVERIFY(lastTimestamp <= time); - lastTimestamp = time; - qmlMessages.append(QQmlProfilerData(time, QQmlProfilerDefinitions::Event, type, - QString::number(a) + QLatin1Char('x') + - QString::number(b))); -} - -void QQmlProfilerTestClient::unknownEvent(QQmlProfilerDefinitions::Message messageType, qint64 time, - int detailType) -{ - QFAIL(qPrintable(QString::fromLatin1("Unknown event %1 with detail type %2 received at %3.") - .arg(messageType).arg(detailType).arg(time))); -} - -void QQmlProfilerTestClient::unknownData(QPacket &stream) -{ - QFAIL(qPrintable(QString::fromLatin1("%1 bytes of extra data after receiving message.") - .arg(stream.device()->bytesAvailable()))); -} - -void QQmlProfilerTestClient::complete() -{ - emit recordingFinished(); -} - -class tst_QQmlProfilerService : public QQmlDataTest +class tst_QQmlProfilerService : public QQmlDebugTest { Q_OBJECT -public: - tst_QQmlProfilerService() - : m_process(0) - , m_connection(0) - , m_client(0) - { - } - - private: - QQmlDebugProcess *m_process; - QQmlDebugConnection *m_connection; - QQmlProfilerTestClient *m_client; - enum MessageListType { MessageListQML, MessageListJavaScript, @@ -290,18 +189,26 @@ private: CheckLine = 1 << 2, CheckColumn = 1 << 3, CheckDataEndsWith = 1 << 4, + CheckFileEndsWith = 1 << 5, + CheckNumbers = 1 << 6, - CheckAll = CheckMessageType | CheckDetailType | CheckLine | CheckColumn | CheckDataEndsWith + CheckType = CheckMessageType | CheckDetailType | CheckLine | CheckColumn | CheckFileEndsWith }; - void connect(bool block, const QString &testFile, bool restrictServices = true); + ConnectResult connect(bool block, const QString &testFile, bool recordFromStart = true, + uint flushInterval = 0, bool restrictServices = true); + void checkProcessTerminated(); void checkTraceReceived(); void checkJsHeap(); - bool verify(MessageListType type, int expectedPosition, const QQmlProfilerData &expected, - quint32 checks); + bool verify(MessageListType type, int expectedPosition, + const QQmlProfilerEventType &expectedType, quint32 checks, + const QVector<qint64> &numbers); + + QList<QQmlDebugClient *> createClients() override; + QScopedPointer<QQmlProfilerTestClient> m_client; private slots: - void cleanup(); + void cleanup() override; void connect_data(); void connect(); @@ -312,55 +219,69 @@ private slots: void signalSourceLocation(); void javascript(); void flushInterval(); + void translationBinding(); void memory(); + +private: + bool m_recordFromStart = true; + bool m_flushInterval = 0; + bool m_isComplete = false; + + // Don't use ({...}) here as MSVC will interpret that as the "QVector(int size)" ctor. + const QVector<qint64> m_rangeStart = (QVector<qint64>() << QQmlProfilerDefinitions::RangeStart); + const QVector<qint64> m_rangeEnd = (QVector<qint64>() << QQmlProfilerDefinitions::RangeEnd); }; -#define VERIFY(type, position, expected, checks) QVERIFY(verify(type, position, expected, checks)) +#define VERIFY(type, position, expected, checks, numbers) \ + QVERIFY(verify(type, position, expected, checks, numbers)) -void tst_QQmlProfilerService::connect(bool block, const QString &testFile, bool restrictServices) +QQmlDebugTest::ConnectResult tst_QQmlProfilerService::connect( + bool block, const QString &file, bool recordFromStart, uint flushInterval, + bool restrictServices) { + m_recordFromStart = recordFromStart; + m_flushInterval = flushInterval; + m_isComplete = false; + // ### Still using qmlscene due to QTBUG-33377 - const QString executable = QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene"; - QStringList arguments; - arguments << QString::fromLatin1("-qmljsdebugger=port:%1,%2%3%4") - .arg(STR_PORT_FROM).arg(STR_PORT_TO) - .arg(block ? QStringLiteral(",block") : QString()) - .arg(restrictServices ? QStringLiteral(",services:CanvasFrameRate") : QString()) - << QQmlDataTest::instance()->testFile(testFile); - - m_process = new QQmlDebugProcess(executable, this); - m_process->start(QStringList() << arguments); - QVERIFY2(m_process->waitForSessionStart(), "Could not launch application, or did not get 'Waiting for connection'."); - - m_connection = new QQmlDebugConnection(); - m_client = new QQmlProfilerTestClient(m_connection); - QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(m_connection); - - const int port = m_process->debugPort(); - m_connection->connectToHost(QLatin1String("127.0.0.1"), port); - QVERIFY(m_client); - QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled); + return QQmlDebugTest::connect( + QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmlscene", + restrictServices ? QQmlDebuggingEnabler::profilerServices().join(',') : QString(), + testFile(file), block); +} - foreach (QQmlDebugClient *other, others) - QCOMPARE(other->state(), restrictServices ? QQmlDebugClient::Unavailable : - QQmlDebugClient::Enabled); - qDeleteAll(others); +void tst_QQmlProfilerService::checkProcessTerminated() +{ + // If the process ends before connect(), we get a non-success value from connect() + // That's not a problem as we will still receive the trace. We check that process has terminated + // cleanly here. + + // Wait for the process to finish by itself, if that hasn't happened already + QVERIFY(m_client); + QVERIFY(m_client->client); + QTRY_COMPARE(m_client->client->state(), QQmlDebugClient::NotConnected); + QVERIFY(m_process); + QTRY_COMPARE(m_process->exitStatus(), QProcess::NormalExit); } void tst_QQmlProfilerService::checkTraceReceived() { - QVERIFY2(QQmlDebugTest::waitForSignal(m_client, SIGNAL(recordingFinished())), - "No trace received in time."); + QTRY_VERIFY2(m_isComplete, "No trace received in time."); + + QVector<qint64> numbers; // must start with "StartTrace" - QQmlProfilerData expected(0, QQmlProfilerDefinitions::Event, - QQmlProfilerDefinitions::StartTrace); - VERIFY(MessageListAsynchronous, 0, expected, CheckMessageType | CheckDetailType); + QQmlProfilerEventType expected(QQmlProfilerDefinitions::Event, + QQmlProfilerDefinitions::MaximumRangeType, + QQmlProfilerDefinitions::StartTrace); + VERIFY(MessageListAsynchronous, 0, expected, CheckMessageType | CheckDetailType, numbers); // must end with "EndTrace" - expected.detailType = QQmlProfilerDefinitions::EndTrace; + expected = QQmlProfilerEventType(QQmlProfilerDefinitions::Event, + QQmlProfilerDefinitions::MaximumRangeType, + QQmlProfilerDefinitions::EndTrace); VERIFY(MessageListAsynchronous, m_client->asynchronousMessages.length() - 1, expected, - CheckMessageType | CheckDetailType); + CheckMessageType | CheckDetailType, numbers); } void tst_QQmlProfilerService::checkJsHeap() @@ -373,33 +294,35 @@ void tst_QQmlProfilerService::checkJsHeap() qint64 allocated = 0; qint64 used = 0; qint64 lastTimestamp = -1; - foreach (const QQmlProfilerData &message, m_client->jsHeapMessages) { - switch (message.detailType) { + foreach (const QQmlProfilerEvent &message, m_client->jsHeapMessages) { + const qint64 amount = message.number<qint64>(0); + const QQmlProfilerEventType &type = m_client->types.at(message.typeIndex()); + switch (type.detailType()) { case QV4::Profiling::HeapPage: - allocated += message.amount; + allocated += amount; seen_alloc = true; break; case QV4::Profiling::SmallItem: - used += message.amount; + used += amount; seen_small = true; break; case QV4::Profiling::LargeItem: - allocated += message.amount; - used += message.amount; + allocated += amount; + used += amount; seen_large = true; break; } - QVERIFY(message.time >= lastTimestamp); + QVERIFY(message.timestamp() >= lastTimestamp); // The heap will only be consistent after all events of the same timestamp are processed. if (lastTimestamp == -1) { - lastTimestamp = message.time; + lastTimestamp = message.timestamp(); continue; - } else if (message.time == lastTimestamp) { + } else if (message.timestamp() == lastTimestamp) { continue; } - lastTimestamp = message.time; + lastTimestamp = message.timestamp(); QVERIFY2(used >= 0, QString::fromLatin1("Negative memory usage seen: %1") .arg(used).toUtf8().constData()); @@ -418,10 +341,10 @@ void tst_QQmlProfilerService::checkJsHeap() } bool tst_QQmlProfilerService::verify(tst_QQmlProfilerService::MessageListType type, - int expectedPosition, const QQmlProfilerData &expected, - quint32 checks) + int expectedPosition, const QQmlProfilerEventType &expected, + quint32 checks, const QVector<qint64> &expectedNumbers) { - QVector<QQmlProfilerData> *target = 0; + const QVector<QQmlProfilerEvent> *target = 0; switch (type) { case MessageListQML: target = &(m_client->qmlMessages); break; case MessageListJavaScript: target = &(m_client->javascriptMessages); break; @@ -437,41 +360,81 @@ bool tst_QQmlProfilerService::verify(tst_QQmlProfilerService::MessageListType ty } uint position = expectedPosition; - qint64 timestamp = target->at(expectedPosition).time; - while (position > 0 && target->at(position - 1).time == timestamp) + qint64 timestamp = target->at(expectedPosition).timestamp(); + while (position > 0 && target->at(position - 1).timestamp() == timestamp) --position; QStringList warnings; do { - const QQmlProfilerData &actual = target->at(position); - if ((checks & CheckMessageType) && actual.messageType != expected.messageType) { - warnings << QString::fromLatin1("%1: unexpected messageType. actual: %2 - expected: %3") - .arg(position).arg(actual.messageType).arg(expected.messageType); + const QQmlProfilerEvent &event = target->at(position); + const QQmlProfilerEventType &actual = m_client->types.at(event.typeIndex()); + if ((checks & CheckMessageType) && + (actual.message() != expected.message() + || actual.rangeType() != expected.rangeType())) { + warnings << QString::fromLatin1("%1: unexpected messageType or rangeType. " + "actual: %2, %3 - expected: %4, %5") + .arg(position).arg(actual.message()).arg(actual.rangeType()) + .arg(expected.message()).arg(expected.rangeType()); continue; } - if ((checks & CheckDetailType) && actual.detailType != expected.detailType) { + if ((checks & CheckDetailType) && actual.detailType() != expected.detailType()) { warnings << QString::fromLatin1("%1: unexpected detailType. actual: %2 - expected: %3") - .arg(position).arg(actual.detailType).arg(expected.detailType); + .arg(position).arg(actual.detailType()).arg(expected.detailType()); continue; } - if ((checks & CheckLine) && actual.line != expected.line) { + + const QQmlProfilerEventLocation expectedLocation = expected.location(); + const QQmlProfilerEventLocation actualLocation = actual.location(); + + if ((checks & CheckLine) && actualLocation.line() != expectedLocation.line()) { warnings << QString::fromLatin1("%1: unexpected line. actual: %2 - expected: %3") - .arg(position).arg(actual.line).arg(expected.line); + .arg(position).arg(actualLocation.line()) + .arg(expectedLocation.line()); continue; } - if ((checks & CheckColumn) && actual.column != expected.column) { + if ((checks & CheckColumn) && actualLocation.column() != expectedLocation.column()) { warnings << QString::fromLatin1("%1: unexpected column. actual: %2 - expected: %3") - .arg(position).arg(actual.column).arg(expected.column); + .arg(position).arg(actualLocation.column()) + .arg(expectedLocation.column()); + continue; + } + if ((checks & CheckFileEndsWith) && + !actualLocation.filename().endsWith(expectedLocation.filename())) { + warnings << QString::fromLatin1("%1: unexpected fileName. actual: %2 - expected: %3") + .arg(position).arg(actualLocation.filename()) + .arg(expectedLocation.filename()); continue; } - if ((checks & CheckDataEndsWith) && !actual.detailData.endsWith(expected.detailData)) { + + if ((checks & CheckDataEndsWith) && !actual.data().endsWith(expected.data())) { warnings << QString::fromLatin1("%1: unexpected detailData. actual: %2 - expected: %3") - .arg(position).arg(actual.detailData).arg(expected.detailData); + .arg(position).arg(actual.data()).arg(expected.data()); continue; } + + if (checks & CheckNumbers) { + const QVector<qint64> actualNumbers = event.numbers<QVector<qint64>>(); + if (actualNumbers != expectedNumbers) { + + QStringList expectedList; + for (qint64 number : expectedNumbers) + expectedList.append(QString::number(number)); + QStringList actualList; + for (qint64 number : actualNumbers) + actualList.append(QString::number(number)); + + warnings << QString::fromLatin1( + "%1: unexpected numbers. actual [%2] - expected: [%3]") + .arg(position) + .arg(actualList.join(QLatin1String(", "))) + .arg(expectedList.join(QLatin1String(", "))); + continue; + } + } + return true; - } while (target->at(++position).time == timestamp); + } while (target->at(++position).timestamp() == timestamp); foreach (const QString &message, warnings) qWarning() << message.toLocal8Bit().constData(); @@ -479,54 +442,62 @@ bool tst_QQmlProfilerService::verify(tst_QQmlProfilerService::MessageListType ty return false; } +QList<QQmlDebugClient *> tst_QQmlProfilerService::createClients() +{ + m_client.reset(new QQmlProfilerTestClient(m_connection)); + m_client->client->setRecording(m_recordFromStart); + m_client->client->setFlushInterval(m_flushInterval); + QObject::connect(m_client->client, &QQmlProfilerClient::complete, + this, [this](){ m_isComplete = true; }); + return QList<QQmlDebugClient *>({m_client->client}); +} + void tst_QQmlProfilerService::cleanup() { + auto log = [this](const QQmlProfilerEvent &data, int i) { + const QQmlProfilerEventType &type = m_client->types.at(data.typeIndex()); + const QQmlProfilerEventLocation location = type.location(); + qDebug() << i << data.timestamp() << type.message() << type.rangeType() << type.detailType() + << location.filename() << location.line() << location.column() + << data.numbers<QVector<qint64>>(); + }; + if (m_client && QTest::currentTestFailed()) { qDebug() << "QML Messages:" << m_client->qmlMessages.count(); int i = 0; - foreach (const QQmlProfilerData &data, m_client->qmlMessages) { - qDebug() << i++ << data.time << data.messageType << data.detailType << data.detailData - << data.line << data.column; - } + for (const QQmlProfilerEvent &data : qAsConst(m_client->qmlMessages)) + log(data, i++); + qDebug() << " "; qDebug() << "JavaScript Messages:" << m_client->javascriptMessages.count(); i = 0; - foreach (const QQmlProfilerData &data, m_client->javascriptMessages) { - qDebug() << i++ << data.time << data.messageType << data.detailType << data.detailData - << data.line << data.column; - } + + for (const QQmlProfilerEvent &data : qAsConst(m_client->javascriptMessages)) + log(data, i++); + qDebug() << " "; qDebug() << "Asynchronous Messages:" << m_client->asynchronousMessages.count(); i = 0; - foreach (const QQmlProfilerData &data, m_client->asynchronousMessages) { - qDebug() << i++ << data.time << data.messageType << data.detailType << data.detailData - << data.framerate << data.animationcount << data.line << data.column; - } + for (const QQmlProfilerEvent &data : qAsConst(m_client->asynchronousMessages)) + log(data, i++); + qDebug() << " "; qDebug() << "Pixmap Cache Messages:" << m_client->pixmapMessages.count(); i = 0; - foreach (const QQmlProfilerData &data, m_client->pixmapMessages) { - qDebug() << i++ << data.time << data.messageType << data.detailType << data.detailData - << data.line << data.column; - } + for (const QQmlProfilerEvent &data : qAsConst(m_client->pixmapMessages)) + log(data, i++); + qDebug() << " "; qDebug() << "Javascript Heap Messages:" << m_client->jsHeapMessages.count(); i = 0; - foreach (const QQmlProfilerData &data, m_client->jsHeapMessages) { - qDebug() << i++ << data.time << data.messageType << data.detailType; - } + for (const QQmlProfilerEvent &data : qAsConst(m_client->jsHeapMessages)) + log(data, i++); + qDebug() << " "; - qDebug() << "Process State:" << (m_process ? m_process->state() : QLatin1String("null")); - qDebug() << "Application Output:" << (m_process ? m_process->output() : QLatin1String("null")); - qDebug() << "Connection State:" << QQmlDebugTest::connectionStateString(m_connection); - qDebug() << "Client State:" << QQmlDebugTest::clientStateString(m_client); } - delete m_process; - m_process = 0; - delete m_client; - m_client = 0; - delete m_connection; - m_connection = 0; + + m_client.reset(); + QQmlDebugTest::cleanup(); } void tst_QQmlProfilerService::connect_data() @@ -550,67 +521,62 @@ void tst_QQmlProfilerService::connect() QFETCH(bool, restrictMode); QFETCH(bool, traceEnabled); - connect(blockMode, "test.qml", restrictMode); + QCOMPARE(connect(blockMode, "test.qml", traceEnabled, 0, restrictMode), ConnectSuccess); - // if the engine is waiting, then the first message determines if it starts with trace enabled if (!traceEnabled) - m_client->sendRecordingStatus(false); - m_client->sendRecordingStatus(true); - m_client->sendRecordingStatus(false); + m_client->client->setRecording(true); + m_client->client->setRecording(false); checkTraceReceived(); checkJsHeap(); } void tst_QQmlProfilerService::pixmapCacheData() { - connect(true, "pixmapCacheTest.qml"); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; - m_client->sendRecordingStatus(true); - QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput()))); + QCOMPARE(connect(true, "pixmapCacheTest.qml"), ConnectSuccess); + // Don't wait for readyReadStandardOutput before the loop. It may have already arrived. while (m_process->output().indexOf(QLatin1String("image loaded")) == -1 && m_process->output().indexOf(QLatin1String("image error")) == -1) QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput()))); - m_client->sendRecordingStatus(false); + m_client->client->setRecording(false); checkTraceReceived(); checkJsHeap(); - QQmlProfilerData expected(0, QQmlProfilerDefinitions::PixmapCacheEvent); + auto createType = [](QQmlProfilerDefinitions::PixmapEventType type) { + return QQmlProfilerEventType(QQmlProfilerDefinitions::PixmapCacheEvent, + QQmlProfilerDefinitions::MaximumRangeType, type); + }; + + QVector<qint64> numbers; // image starting to load - expected.detailType = QQmlProfilerDefinitions::PixmapLoadingStarted; - VERIFY(MessageListPixmap, 0, expected, CheckMessageType | CheckDetailType); + VERIFY(MessageListPixmap, 0, createType(QQmlProfilerDefinitions::PixmapLoadingStarted), + CheckMessageType | CheckDetailType, numbers); // image size - expected.detailType = QQmlProfilerDefinitions::PixmapSizeKnown; - expected.line = expected.column = 2; // width and height, in fact - VERIFY(MessageListPixmap, 1, expected, - CheckMessageType | CheckDetailType | CheckLine | CheckColumn); + numbers = QVector<qint64>({2, 2, 1}); + VERIFY(MessageListPixmap, 1, createType(QQmlProfilerDefinitions::PixmapSizeKnown), + CheckMessageType | CheckDetailType | CheckNumbers, numbers); // image loaded - expected.detailType = QQmlProfilerDefinitions::PixmapLoadingFinished; - VERIFY(MessageListPixmap, 2, expected, CheckMessageType | CheckDetailType); + VERIFY(MessageListPixmap, 2, createType(QQmlProfilerDefinitions::PixmapLoadingFinished), + CheckMessageType | CheckDetailType, numbers); // cache size - expected.detailType = QQmlProfilerDefinitions::PixmapCacheCountChanged; - VERIFY(MessageListPixmap, 3, expected, CheckMessageType | CheckDetailType); + VERIFY(MessageListPixmap, 3, createType(QQmlProfilerDefinitions::PixmapCacheCountChanged), + CheckMessageType | CheckDetailType, numbers); } void tst_QQmlProfilerService::scenegraphData() { - connect(true, "scenegraphTest.qml"); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; - - m_client->sendRecordingStatus(true); + QCOMPARE(connect(true, "scenegraphTest.qml"), ConnectSuccess); while (!m_process->output().contains(QLatin1String("tick"))) QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput()))); - m_client->sendRecordingStatus(false); + m_client->client->setRecording(false); checkTraceReceived(); checkJsHeap(); @@ -625,34 +591,39 @@ void tst_QQmlProfilerService::scenegraphData() qint64 contextFrameTime = -1; qint64 renderFrameTime = -1; #if QT_CONFIG(opengl) //Software renderer doesn't have context frames - foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) { - if (msg.messageType == QQmlProfilerDefinitions::SceneGraphFrame) { - if (msg.detailType == QQmlProfilerDefinitions::SceneGraphContextFrame) { - contextFrameTime = msg.time; - break; + if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) { + foreach (const QQmlProfilerEvent &msg, m_client->asynchronousMessages) { + const QQmlProfilerEventType &type = m_client->types.at(msg.typeIndex()); + if (type.message() == QQmlProfilerDefinitions::SceneGraphFrame) { + if (type.detailType() == QQmlProfilerDefinitions::SceneGraphContextFrame) { + contextFrameTime = msg.timestamp(); + break; + } } } - } - QVERIFY(contextFrameTime != -1); + QVERIFY(contextFrameTime != -1); + } #endif - foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) { - if (msg.detailType == QQmlProfilerDefinitions::SceneGraphRendererFrame) { - QVERIFY(msg.time >= contextFrameTime); - renderFrameTime = msg.time; + foreach (const QQmlProfilerEvent &msg, m_client->asynchronousMessages) { + const QQmlProfilerEventType &type = m_client->types.at(msg.typeIndex()); + if (type.detailType() == QQmlProfilerDefinitions::SceneGraphRendererFrame) { + QVERIFY(msg.timestamp() >= contextFrameTime); + renderFrameTime = msg.timestamp(); break; } } QVERIFY(renderFrameTime != -1); - foreach (const QQmlProfilerData &msg, m_client->asynchronousMessages) { - if (msg.detailType == QQmlProfilerDefinitions::SceneGraphRenderLoopFrame) { - if (msg.time >= contextFrameTime) { + foreach (const QQmlProfilerEvent &msg, m_client->asynchronousMessages) { + const QQmlProfilerEventType &type = m_client->types.at(msg.typeIndex()); + if (type.detailType() == QQmlProfilerDefinitions::SceneGraphRenderLoopFrame) { + if (msg.timestamp() >= contextFrameTime) { // Make sure SceneGraphRenderLoopFrame is not between SceneGraphContextFrame and // SceneGraphRendererFrame. A SceneGraphRenderLoopFrame before everything else is // OK as the scene graph might decide to do an initial rendering. - QVERIFY(msg.time >= renderFrameTime); + QVERIFY(msg.timestamp() >= renderFrameTime); break; } } @@ -662,10 +633,7 @@ void tst_QQmlProfilerService::scenegraphData() void tst_QQmlProfilerService::profileOnExit() { connect(true, "exit.qml"); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; - - m_client->sendRecordingStatus(true); + checkProcessTerminated(); checkTraceReceived(); checkJsHeap(); @@ -673,104 +641,108 @@ void tst_QQmlProfilerService::profileOnExit() void tst_QQmlProfilerService::controlFromJS() { - connect(true, "controlFromJS.qml"); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; + QCOMPARE(connect(true, "controlFromJS.qml", false), ConnectSuccess); - m_client->sendRecordingStatus(false); + m_client->client->setRecording(false); checkTraceReceived(); checkJsHeap(); } void tst_QQmlProfilerService::signalSourceLocation() { - connect(true, "signalSourceLocation.qml"); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; + QCOMPARE(connect(true, "signalSourceLocation.qml"), ConnectSuccess); - m_client->sendRecordingStatus(true); while (!(m_process->output().contains(QLatin1String("500")))) QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput()))); - m_client->sendRecordingStatus(false); + m_client->client->setRecording(false); checkTraceReceived(); checkJsHeap(); - QQmlProfilerData expected(0, QQmlProfilerDefinitions::RangeLocation, - QQmlProfilerDefinitions::HandlingSignal, - QLatin1String("signalSourceLocation.qml")); - expected.line = 8; - expected.column = 28; - VERIFY(MessageListQML, 9, expected, CheckAll); + auto createType = [](int line, int column) { + return QQmlProfilerEventType( + QQmlProfilerDefinitions::MaximumMessage, + QQmlProfilerDefinitions::HandlingSignal, -1, + QQmlProfilerEventLocation(QLatin1String("signalSourceLocation.qml"), line, + column)); + }; - expected.line = 7; - expected.column = 21; - VERIFY(MessageListQML, 11, expected, CheckAll); + VERIFY(MessageListQML, 4, createType(8, 28), CheckType | CheckNumbers, m_rangeStart); + VERIFY(MessageListQML, 6, createType(7, 21), CheckType | CheckNumbers, m_rangeEnd); } void tst_QQmlProfilerService::javascript() { - connect(true, "javascript.qml"); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; + QCOMPARE(connect(true, "javascript.qml"), ConnectSuccess); - m_client->sendRecordingStatus(true); while (!(m_process->output().contains(QLatin1String("done")))) QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput()))); - m_client->sendRecordingStatus(false); + m_client->client->setRecording(false); checkTraceReceived(); checkJsHeap(); - QQmlProfilerData expected(0, QQmlProfilerDefinitions::RangeStart, - QQmlProfilerDefinitions::Javascript); - VERIFY(MessageListJavaScript, 6, expected, CheckMessageType | CheckDetailType); + VERIFY(MessageListJavaScript, 2, QQmlProfilerEventType(QQmlProfilerDefinitions::MaximumMessage, + QQmlProfilerDefinitions::Javascript), + CheckMessageType | CheckDetailType | CheckNumbers, m_rangeStart); - expected.messageType = QQmlProfilerDefinitions::RangeLocation; - expected.detailData = QLatin1String("javascript.qml"); - expected.line = 4; - expected.column = 5; - VERIFY(MessageListJavaScript, 7, expected, CheckAll); + VERIFY(MessageListJavaScript, 3, + QQmlProfilerEventType(QQmlProfilerDefinitions::MaximumMessage, + QQmlProfilerDefinitions::Javascript, -1, + QQmlProfilerEventLocation(QLatin1String("javascript.qml"), 4, 5)), + CheckType | CheckNumbers, m_rangeStart); - expected.messageType = QQmlProfilerDefinitions::RangeData; - expected.detailData = QLatin1String("something"); - VERIFY(MessageListJavaScript, 8, expected, - CheckMessageType | CheckDetailType | CheckDataEndsWith); + VERIFY(MessageListJavaScript, 4, QQmlProfilerEventType( + QQmlProfilerDefinitions::MaximumMessage, QQmlProfilerDefinitions::Javascript, -1, + QQmlProfilerEventLocation(), QLatin1String("something")), + CheckMessageType | CheckDetailType | CheckDataEndsWith | CheckNumbers, m_rangeStart); - expected.messageType = QQmlProfilerDefinitions::RangeEnd; - VERIFY(MessageListJavaScript, 21, expected, CheckMessageType | CheckDetailType); + VERIFY(MessageListJavaScript, 10, QQmlProfilerEventType(QQmlProfilerDefinitions::MaximumMessage, + QQmlProfilerDefinitions::Javascript), + CheckMessageType | CheckDetailType | CheckNumbers, m_rangeEnd); } void tst_QQmlProfilerService::flushInterval() { - connect(true, "timer.qml"); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; - - m_client->sendRecordingStatus(true, -1, 1); + QCOMPARE(connect(true, "timer.qml", true, 1), ConnectSuccess); // Make sure we get multiple messages QTRY_VERIFY(m_client->qmlMessages.length() > 0); QVERIFY(m_client->qmlMessages.length() < 100); QTRY_VERIFY(m_client->qmlMessages.length() > 100); - m_client->sendRecordingStatus(false); + m_client->client->setRecording(false); checkTraceReceived(); checkJsHeap(); } +void tst_QQmlProfilerService::translationBinding() +{ + connect(true, "qstr.qml"); + checkProcessTerminated(); + + checkTraceReceived(); + checkJsHeap(); + + const QQmlProfilerEventType type(QQmlProfilerDefinitions::MaximumMessage, + QQmlProfilerDefinitions::Binding); + + VERIFY(MessageListQML, 4, type, CheckDetailType | CheckMessageType | CheckNumbers, + m_rangeStart); + VERIFY(MessageListQML, 5, type, CheckDetailType | CheckMessageType | CheckNumbers, + m_rangeEnd); +} + void tst_QQmlProfilerService::memory() { connect(true, "memory.qml"); - if (QTest::currentTestFailed() || QTestResult::skipCurrentTest()) - return; - - m_client->sendRecordingStatus(true); + checkProcessTerminated(); checkTraceReceived(); checkJsHeap(); int smallItems = 0; for (auto message : m_client->jsHeapMessages) { - if (message.detailType == QV4::Profiling::SmallItem) + const QQmlProfilerEventType &type = m_client->types[message.typeIndex()]; + if (type.detailType() == QV4::Profiling::SmallItem) ++smallItems; } diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp index 441f8c113f..b569ad6b3c 100644 --- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp +++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp @@ -38,7 +38,6 @@ #include <private/qv4debugging_p.h> #include <private/qv8engine_p.h> #include <private/qv4objectiterator_p.h> -#include <private/qv4isel_moth_p.h> #include <private/qv4string_p.h> #include <private/qqmlbuiltinfunctions_p.h> #include <private/qqmldebugservice_p.h> @@ -46,7 +45,7 @@ using namespace QV4; using namespace QV4::Debugging; -typedef void (*InjectedFunction)(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *callData); +typedef QV4::ReturnedValue (*InjectedFunction)(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int); Q_DECLARE_METATYPE(InjectedFunction) static bool waitForSignal(QObject* obj, const char* signal, int timeout = 10000) @@ -79,7 +78,7 @@ public: emit evaluateFinished(); } - QV4::ExecutionEngine *v4Engine() { return QV8Engine::getV4(this); } + QV4::ExecutionEngine *v4Engine() { return handle(); } Q_INVOKABLE void injectFunction(const QString &functionName, InjectedFunction injectedFunction) { @@ -88,7 +87,7 @@ public: QV4::ScopedString name(scope, v4->newString(functionName)); QV4::ScopedContext ctx(scope, v4->rootContext()); - QV4::ScopedValue function(scope, BuiltinFunction::create(ctx, name, injectedFunction)); + QV4::ScopedValue function(scope, FunctionObject::createBuiltinFunction(ctx, name, injectedFunction)); v4->globalObject->put(name, function); } @@ -343,7 +342,6 @@ void tst_qv4debugger::init() m_javaScriptThread = new QThread; m_engine = new TestEngine; m_v4 = m_engine->v4Engine(); - m_v4->iselFactory.reset(new QV4::Moth::ISelFactory); m_v4->setDebugger(new QV4Debugger(m_v4)); m_engine->moveToThread(m_javaScriptThread); m_javaScriptThread->start(); @@ -438,9 +436,9 @@ void tst_qv4debugger::addBreakPointWhilePaused() QCOMPARE(state.lineNumber, 2); } -static void someCall(const QV4::BuiltinFunction *, QV4::Scope &scope, QV4::CallData *) +static QV4::ReturnedValue someCall(const FunctionObject *function, const QV4::Value *, const QV4::Value *, int) { - static_cast<QV4Debugger *>(scope.engine->debugger()) + static_cast<QV4Debugger *>(function->engine()->debugger()) ->removeBreakPoint("removeBreakPointForNextInstruction", 2); RETURN_UNDEFINED(); } @@ -464,7 +462,7 @@ void tst_qv4debugger::conditionalBreakPoint() { m_debuggerAgent->m_captureContextInfo = true; QString script = - "function test() {\n" + "var test = function() {\n" " for (var i = 0; i < 15; ++i) {\n" " var x = i;\n" " }\n" @@ -489,9 +487,8 @@ void tst_qv4debugger::conditionalBreakPoint() void tst_qv4debugger::conditionalBreakPointInQml() { QQmlEngine engine; - QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine); + QV4::ExecutionEngine *v4 = engine.handle(); QV4Debugger *v4Debugger = new QV4Debugger(v4); - v4->iselFactory.reset(new QV4::Moth::ISelFactory); v4->setDebugger(v4Debugger); QScopedPointer<QThread> debugThread(new QThread); @@ -531,7 +528,7 @@ void tst_qv4debugger::readArguments() m_debuggerAgent->m_captureContextInfo = true; QString script = - "function f(a, b, c, d) {\n" + "var f = function(a, b, c, d) {\n" " return a === b\n" "}\n" "var four;\n" @@ -557,7 +554,7 @@ void tst_qv4debugger::readLocals() m_debuggerAgent->m_captureContextInfo = true; QString script = - "function f(a, b) {\n" + "var f = function(a, b) {\n" " var c = a + b\n" " var d = a - b\n" // breakpoint, c should be set, d should be undefined " return c === d\n" @@ -583,7 +580,7 @@ void tst_qv4debugger::readObject() m_debuggerAgent->m_captureContextInfo = true; QString script = - "function f(a) {\n" + "var f = function(a) {\n" " var b = a\n" " return b\n" "}\n" @@ -630,7 +627,7 @@ void tst_qv4debugger::readObject() QCOMPARE(b_tail_head.value("value").toString(), QStringLiteral("asdf")); QJsonObject b_tail_tail = b_tail_props.at(1).toObject(); QCOMPARE(b_tail_tail.value("name").toString(), QStringLiteral("tail")); - QCOMPARE(b_tail_tail.value("type").toString(), QStringLiteral("null")); + QCOMPARE(b_tail_tail.value("type").toString(), QStringLiteral("object")); QVERIFY(b_tail_tail.value("value").isNull()); } @@ -641,7 +638,7 @@ void tst_qv4debugger::readContextInAllFrames() m_debuggerAgent->m_captureContextInfo = true; QString script = - "function fact(n) {\n" + "var fact = function(n) {\n" " if (n > 1) {\n" " var n_1 = n - 1;\n" " n_1 = fact(n_1);\n" @@ -814,13 +811,13 @@ void tst_qv4debugger::lastLineOfConditional_data() QTest::newRow("do..while {block}") << "do {\n" << "} while (ret < 10);" << 4 << 7; QTest::newRow("if true {block}") << "if (true) {\n" << "}" - << 4 << 7; + << 4 << 8; QTest::newRow("if false {block}") << "if (false) {\n" << "}" << 2 << 8; QTest::newRow("if true else {block}") << "if (true) {\n" << "} else {\n ret += 8;\n}" - << 4 << 7; + << 4 << 10; QTest::newRow("if false else {block}") << "if (false) {\n" << "} else {\n ret += 8;\n}" - << 8 << 9; + << 8 << 10; QTest::newRow("for statement") << "for (var i = 0; i < 10; ++i)\n" << "" << 4 << 2; QTest::newRow("for..in statement") << "for (var i in [0, 1, 2, 3, 4])\n" << "" << 4 << 2; @@ -829,11 +826,11 @@ void tst_qv4debugger::lastLineOfConditional_data() // For two nested if statements without blocks, we need to map the jump from the inner to the // outer one on the outer "if". There is just no better place. - QTest::newRow("if true statement") << "if (true)\n" << "" << 4 << 2; + QTest::newRow("if true statement") << "if (true)\n" << "" << 4 << 8; QTest::newRow("if false statement") << "if (false)\n" << "" << 2 << 8; // Also two nested ifs without blocks. - QTest::newRow("if true else statement") << "if (true)\n" << "else\n ret += 8;" << 4 << 2; + QTest::newRow("if true else statement") << "if (true)\n" << "else\n ret += 8;" << 4 << 9; QTest::newRow("if false else statement") << "if (false)\n" << "else\n ret += 8;" << 8 << 9; } diff --git a/tests/auto/qml/debugger/shared/debugutil.cpp b/tests/auto/qml/debugger/shared/debugutil.cpp index d31efc84cf..8ecbe53822 100644 --- a/tests/auto/qml/debugger/shared/debugutil.cpp +++ b/tests/auto/qml/debugger/shared/debugutil.cpp @@ -27,13 +27,14 @@ ****************************************************************************/ #include "debugutil_p.h" +#include "qqmldebugprocess_p.h" #include <private/qqmldebugconnection_p.h> +#include <QtQml/qqmldebug.h> + #include <QtCore/qeventloop.h> #include <QtCore/qtimer.h> -#include <QtCore/qfileinfo.h> -#include <QtCore/qdir.h> bool QQmlDebugTest::waitForSignal(QObject *receiver, const char *member, int timeout) { QEventLoop loop; @@ -116,192 +117,114 @@ void QQmlDebugTestClient::messageReceived(const QByteArray &ba) emit serverMessage(ba); } -QQmlDebugProcess::QQmlDebugProcess(const QString &executable, QObject *parent) - : QObject(parent) - , m_executable(executable) - , m_started(false) - , m_port(0) - , m_maximumBindErrors(0) - , m_receivedBindErrors(0) -{ - m_process.setProcessChannelMode(QProcess::MergedChannels); - m_timer.setSingleShot(true); - m_timer.setInterval(15000); - connect(&m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(processAppOutput())); - connect(&m_process, SIGNAL(errorOccurred(QProcess::ProcessError)), - this, SLOT(processError(QProcess::ProcessError))); - connect(&m_timer, SIGNAL(timeout()), SLOT(timeout())); -} +template<typename F> +struct Finalizer { + F m_lambda; + Finalizer(F &&lambda) : m_lambda(std::forward<F>(lambda)) {} + ~Finalizer() { m_lambda(); } +}; -QQmlDebugProcess::~QQmlDebugProcess() +template<typename F> +static Finalizer<F> defer(F &&lambda) { - stop(); + return Finalizer<F>(std::forward<F>(lambda)); } -QString QQmlDebugProcess::state() +QQmlDebugTest::ConnectResult QQmlDebugTest::connect( + const QString &executable, const QString &services, const QString &extraArgs, + bool block) { - QString stateStr; - switch (m_process.state()) { - case QProcess::NotRunning: { - stateStr = "not running"; - if (m_process.exitStatus() == QProcess::CrashExit) - stateStr += " (crashed!)"; - else - stateStr += ", return value " + QString::number(m_process.exitCode()); - break; - } - case QProcess::Starting: stateStr = "starting"; break; - case QProcess::Running: stateStr = "running"; break; - } - return stateStr; -} + QStringList arguments; + arguments << QString::fromLatin1("-qmljsdebugger=port:13773,13783%3%4") + .arg(block ? QStringLiteral(",block") : QString()) + .arg(services.isEmpty() ? services : (QStringLiteral(",services:") + services)) + << extraArgs; -void QQmlDebugProcess::start(const QStringList &arguments) -{ -#ifdef Q_OS_MAC - // make sure m_executable points to the actual binary even if it's inside an app bundle - QFileInfo binFile(m_executable); - if (!binFile.isExecutable()) { - QDir bundleDir(m_executable + ".app"); - if (bundleDir.exists()) { - m_executable = bundleDir.absoluteFilePath("Contents/MacOS/" + binFile.baseName()); - //qDebug() << Q_FUNC_INFO << "found bundled binary" << m_executable; - } - } -#endif - m_mutex.lock(); - m_port = 0; - m_process.setEnvironment(QProcess::systemEnvironment() + m_environment); - m_process.start(m_executable, arguments); - if (!m_process.waitForStarted()) { - qWarning() << "QML Debug Client: Could not launch app " << m_executable - << ": " << m_process.errorString(); - m_eventLoop.quit(); - } else { - m_timer.start(); - } - m_mutex.unlock(); -} + m_process = createProcess(executable); + if (!m_process) + return ProcessFailed; -void QQmlDebugProcess::stop() -{ - if (m_process.state() != QProcess::NotRunning) { - m_process.kill(); - m_process.waitForFinished(5000); - } -} + m_process->start(QStringList() << arguments); + if (!m_process->waitForSessionStart()) + return SessionFailed; -void QQmlDebugProcess::setMaximumBindErrors(int ignore) -{ - m_maximumBindErrors = ignore; -} + m_connection = createConnection(); + if (!m_connection) + return ConnectionFailed; -void QQmlDebugProcess::timeout() -{ - qWarning() << "Timeout while waiting for QML debugging messages " - "in application output. Process is in state" << m_process.state() << ", Output:" << m_output << "."; - m_eventLoop.quit(); -} + m_clients = createClients(); + if (m_clients.contains(nullptr)) + return ClientsFailed; -bool QQmlDebugProcess::waitForSessionStart() -{ - if (m_process.state() != QProcess::Running) { - qWarning() << "Could not start up " << m_executable; - return false; - } else if (m_started) { + auto allEnabled = [this]() { + for (QQmlDebugClient *client : m_clients) { + if (client->state() != QQmlDebugClient::Enabled) + return false; + } return true; + }; + + QList<QQmlDebugClient *> others = createOtherClients(m_connection); + auto deleter = defer([&others]() { qDeleteAll(others); }); + Q_UNUSED(deleter); + + const int port = m_process->debugPort(); + m_connection->connectToHost(QLatin1String("127.0.0.1"), port); + for (int tries = 0; tries < 100 && !allEnabled(); ++tries) + QTest::qWait(50); + if (!allEnabled()) + return EnableFailed; + + const QQmlDebugClient::State expectedState = services.isEmpty() ? QQmlDebugClient::Enabled + : QQmlDebugClient::Unavailable; + for (QQmlDebugClient *other : others) { + if (other->state() != expectedState) + return RestrictFailed; } - m_eventLoop.exec(); - - return m_started; + return ConnectSuccess; } -int QQmlDebugProcess::debugPort() const +QList<QQmlDebugClient *> QQmlDebugTest::createClients() { - return m_port; + return QList<QQmlDebugClient *>(); } -bool QQmlDebugProcess::waitForFinished() +QQmlDebugProcess *QQmlDebugTest::createProcess(const QString &executable) { - return m_process.waitForFinished(); + return new QQmlDebugProcess(executable, this); } -QProcess::ExitStatus QQmlDebugProcess::exitStatus() const +QQmlDebugConnection *QQmlDebugTest::createConnection() { - return m_process.exitStatus(); + return new QQmlDebugConnection(this); } -void QQmlDebugProcess::addEnvironment(const QString &environment) +void QQmlDebugTest::cleanup() { - m_environment.append(environment); -} + if (QTest::currentTestFailed()) { + const QString null = QStringLiteral("null"); -QString QQmlDebugProcess::output() const -{ - return m_output; -} - -void QQmlDebugProcess::processAppOutput() -{ - m_mutex.lock(); - - bool outputFromAppItself = false; - - QString newOutput = m_process.readAll(); - m_output.append(newOutput); - m_outputBuffer.append(newOutput); - - while (true) { - const int nlIndex = m_outputBuffer.indexOf(QLatin1Char('\n')); - if (nlIndex < 0) // no further complete lines - break; - const QString line = m_outputBuffer.left(nlIndex); - m_outputBuffer = m_outputBuffer.right(m_outputBuffer.size() - nlIndex - 1); - - if (line.contains("QML Debugger:")) { - const QRegExp portRx("Waiting for connection on port (\\d+)"); - if (portRx.indexIn(line) != -1) { - m_port = portRx.cap(1).toInt(); - m_timer.stop(); - m_started = true; - m_eventLoop.quit(); - continue; - } - if (line.contains("Unable to listen")) { - if (++m_receivedBindErrors >= m_maximumBindErrors) { - if (m_maximumBindErrors == 0) - qWarning() << "App was unable to bind to port!"; - m_timer.stop(); - m_eventLoop.quit(); - } - continue; - } - } else { - // set to true if there is output not coming from the debugger - outputFromAppItself = true; + qDebug() << "Process State:" << (m_process ? m_process->state() : null); + qDebug() << "Application Output:" << (m_process ? m_process->output() : null); + qDebug() << "Connection State:" << QQmlDebugTest::connectionStateString(m_connection); + for (QQmlDebugClient *client : m_clients) { + if (client) + qDebug() << client->name() << "State:" << QQmlDebugTest::clientStateString(client); + else + qDebug() << "Failed Client:" << null; } } - m_mutex.unlock(); - if (outputFromAppItself) - emit readyReadStandardOutput(); -} + qDeleteAll(m_clients); + m_clients.clear(); -void QQmlDebugProcess::processError(QProcess::ProcessError error) -{ - if (!m_eventLoop.isRunning()) - return; - - qDebug() << "An error occurred while waiting for debug process to become available:"; - switch (error) { - case QProcess::FailedToStart: qDebug() << "Process failed to start."; break; - case QProcess::Crashed: qDebug() << "Process crashed."; break; - case QProcess::Timedout: qDebug() << "Process timed out."; break; - case QProcess::WriteError: qDebug() << "Error while writing to process."; break; - case QProcess::ReadError: qDebug() << "Error while reading from process."; break; - case QProcess::UnknownError: qDebug() << "Unknown process error."; break; - } + delete m_connection; + m_connection = nullptr; - m_eventLoop.exit(); + if (m_process) { + m_process->stop(); + delete m_process; + m_process = nullptr; + } } diff --git a/tests/auto/qml/debugger/shared/debugutil.pri b/tests/auto/qml/debugger/shared/debugutil.pri index 1983f3583e..13dcdb91d8 100644 --- a/tests/auto/qml/debugger/shared/debugutil.pri +++ b/tests/auto/qml/debugger/shared/debugutil.pri @@ -1,4 +1,11 @@ QT += qmldebug-private -HEADERS += $$PWD/debugutil_p.h -SOURCES += $$PWD/debugutil.cpp +INCLUDEPATH += $$PWD +include($$PWD/../../../shared/util.pri) + +HEADERS += \ + $$PWD/debugutil_p.h \ + $$PWD/qqmldebugprocess_p.h +SOURCES += \ + $$PWD/debugutil.cpp \ + $$PWD/qqmldebugprocess.cpp diff --git a/tests/auto/qml/debugger/shared/debugutil_p.h b/tests/auto/qml/debugger/shared/debugutil_p.h index 1ec0a6513d..94ad83bfce 100644 --- a/tests/auto/qml/debugger/shared/debugutil_p.h +++ b/tests/auto/qml/debugger/shared/debugutil_p.h @@ -1,4 +1,3 @@ - /**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. @@ -41,23 +40,43 @@ // We mean it. // +#include <../../../shared/util.h> #include <private/qqmldebugclient_p.h> -#include <QtCore/qeventloop.h> -#include <QtCore/qtimer.h> -#include <QtCore/qthread.h> -#include <QtCore/qprocess.h> -#include <QtCore/qmutex.h> -#include <QtTest/qtest.h> -#include <QtQml/qqmlengine.h> - -class QQmlDebugTest +class QQmlDebugProcess; +class QQmlDebugTest : public QQmlDataTest { + Q_OBJECT public: static bool waitForSignal(QObject *receiver, const char *member, int timeout = 5000); static QList<QQmlDebugClient *> createOtherClients(QQmlDebugConnection *connection); static QString clientStateString(const QQmlDebugClient *client); static QString connectionStateString(const QQmlDebugConnection *connection); + +protected: + enum ConnectResult { + ConnectSuccess, + ProcessFailed, + SessionFailed, + ConnectionFailed, + ClientsFailed, + EnableFailed, + RestrictFailed + }; + + ConnectResult connect(const QString &executable, const QString &services, + const QString &extraArgs, bool block); + + virtual QQmlDebugProcess *createProcess(const QString &executable); + virtual QQmlDebugConnection *createConnection(); + virtual QList<QQmlDebugClient *> createClients(); + + QQmlDebugProcess *m_process = nullptr; + QQmlDebugConnection *m_connection = nullptr; + QList<QQmlDebugClient *> m_clients; + +protected slots: + virtual void cleanup(); }; class QQmlDebugTestClient : public QQmlDebugClient @@ -80,51 +99,6 @@ private: QByteArray lastMsg; }; -class QQmlDebugProcess : public QObject -{ - Q_OBJECT -public: - QQmlDebugProcess(const QString &executable, QObject *parent = 0); - ~QQmlDebugProcess(); - - QString state(); - - void addEnvironment(const QString &environment); - - void start(const QStringList &arguments); - bool waitForSessionStart(); - int debugPort() const; - - bool waitForFinished(); - QProcess::ExitStatus exitStatus() const; - - QString output() const; - void stop(); - void setMaximumBindErrors(int numErrors); - -signals: - void readyReadStandardOutput(); - -private slots: - void timeout(); - void processAppOutput(); - void processError(QProcess::ProcessError error); - -private: - QString m_executable; - QProcess m_process; - QString m_outputBuffer; - QString m_output; - QTimer m_timer; - QEventLoop m_eventLoop; - QMutex m_mutex; - bool m_started; - QStringList m_environment; - int m_port; - int m_maximumBindErrors; - int m_receivedBindErrors; -}; - class QQmlInspectorResultRecipient : public QObject { Q_OBJECT diff --git a/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp b/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp new file mode 100644 index 0000000000..201a6b1a76 --- /dev/null +++ b/tests/auto/qml/debugger/shared/qqmldebugprocess.cpp @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 "qqmldebugprocess_p.h" + +#include <QtCore/qdebug.h> +#include <QtCore/qfileinfo.h> +#include <QtCore/qdir.h> + +QQmlDebugProcess::QQmlDebugProcess(const QString &executable, QObject *parent) + : QObject(parent) + , m_executable(executable) + , m_state(SessionUnknown) + , m_port(0) + , m_maximumBindErrors(0) + , m_receivedBindErrors(0) +{ + m_process.setProcessChannelMode(QProcess::MergedChannels); + m_timer.setSingleShot(true); + m_timer.setInterval(15000); + connect(&m_process, &QProcess::readyReadStandardOutput, + this, &QQmlDebugProcess::processAppOutput); + connect(&m_process, &QProcess::errorOccurred, + this, &QQmlDebugProcess::processError); + connect(&m_process, QOverload<int>::of(&QProcess::finished), + this, [this]() { + m_timer.stop(); + m_eventLoop.quit(); + }); + connect(&m_timer, &QTimer::timeout, + this, &QQmlDebugProcess::timeout); +} + +QQmlDebugProcess::~QQmlDebugProcess() +{ + stop(); +} + +QString QQmlDebugProcess::state() +{ + QString stateStr; + switch (m_process.state()) { + case QProcess::NotRunning: { + stateStr = "not running"; + if (m_process.exitStatus() == QProcess::CrashExit) + stateStr += " (crashed!)"; + else + stateStr += ", return value " + QString::number(m_process.exitCode()); + break; + } + case QProcess::Starting: + stateStr = "starting"; + break; + case QProcess::Running: + stateStr = "running"; + break; + } + return stateStr; +} + +void QQmlDebugProcess::start(const QStringList &arguments) +{ +#ifdef Q_OS_MAC + // make sure m_executable points to the actual binary even if it's inside an app bundle + QFileInfo binFile(m_executable); + if (!binFile.isExecutable()) { + QDir bundleDir(m_executable + ".app"); + if (bundleDir.exists()) { + m_executable = bundleDir.absoluteFilePath("Contents/MacOS/" + binFile.baseName()); + //qDebug() << Q_FUNC_INFO << "found bundled binary" << m_executable; + } + } +#endif + m_mutex.lock(); + m_port = 0; + m_process.setEnvironment(QProcess::systemEnvironment() + m_environment); + m_process.start(m_executable, arguments); + if (!m_process.waitForStarted()) { + qWarning() << "QML Debug Client: Could not launch app " << m_executable + << ": " << m_process.errorString(); + m_eventLoop.quit(); + } + m_mutex.unlock(); +} + +void QQmlDebugProcess::stop() +{ + if (m_process.state() != QProcess::NotRunning) { + disconnect(&m_process, &QProcess::errorOccurred, this, &QQmlDebugProcess::processError); + m_process.kill(); + m_process.waitForFinished(5000); + } +} + +void QQmlDebugProcess::setMaximumBindErrors(int ignore) +{ + m_maximumBindErrors = ignore; +} + +void QQmlDebugProcess::timeout() +{ + qWarning() << "Timeout while waiting for QML debugging messages " + "in application output. Process is in state" << m_process.state() + << ", Output:" << m_output << "."; + m_eventLoop.quit(); +} + +bool QQmlDebugProcess::waitForSessionStart() +{ + if (m_process.state() != QProcess::Running) { + qWarning() << "Could not start up " << m_executable; + return false; + } else if (m_state == SessionStarted) { + return true; + } else if (m_state == SessionFailed) { + return false; + } + + m_timer.start(); + m_eventLoop.exec(); + + return m_state == SessionStarted; +} + +int QQmlDebugProcess::debugPort() const +{ + return m_port; +} + +bool QQmlDebugProcess::waitForFinished() +{ + return m_process.waitForFinished(); +} + +QProcess::ExitStatus QQmlDebugProcess::exitStatus() const +{ + return m_process.exitStatus(); +} + +void QQmlDebugProcess::addEnvironment(const QString &environment) +{ + m_environment.append(environment); +} + +QString QQmlDebugProcess::output() const +{ + return m_output; +} + +void QQmlDebugProcess::processAppOutput() +{ + m_mutex.lock(); + + bool outputFromAppItself = false; + + QString newOutput = m_process.readAll(); + m_output.append(newOutput); + m_outputBuffer.append(newOutput); + + while (true) { + const int nlIndex = m_outputBuffer.indexOf(QLatin1Char('\n')); + if (nlIndex < 0) // no further complete lines + break; + const QString line = m_outputBuffer.left(nlIndex); + m_outputBuffer = m_outputBuffer.right(m_outputBuffer.size() - nlIndex - 1); + + if (line.contains("QML Debugger:")) { + const QRegExp portRx("Waiting for connection on port (\\d+)"); + if (portRx.indexIn(line) != -1) { + m_port = portRx.cap(1).toInt(); + m_timer.stop(); + m_state = SessionStarted; + m_eventLoop.quit(); + continue; + } + if (line.contains("Unable to listen")) { + if (++m_receivedBindErrors >= m_maximumBindErrors) { + if (m_maximumBindErrors == 0) + qWarning() << "App was unable to bind to port!"; + m_timer.stop(); + m_state = SessionFailed; + m_eventLoop.quit(); + } + continue; + } + } + + // set to true if there is output not coming from the debugger or we don't understand it + outputFromAppItself = true; + } + m_mutex.unlock(); + + if (outputFromAppItself) + emit readyReadStandardOutput(); +} + +void QQmlDebugProcess::processError(QProcess::ProcessError error) +{ + qDebug() << "An error occurred while waiting for debug process to become available:"; + switch (error) { + case QProcess::FailedToStart: + qDebug() << "Process failed to start."; + break; + case QProcess::Crashed: + qDebug() << "Process crashed."; + break; + case QProcess::Timedout: + qDebug() << "Process timed out."; + break; + case QProcess::WriteError: + qDebug() << "Error while writing to process."; + break; + case QProcess::ReadError: + qDebug() << "Error while reading from process."; + break; + case QProcess::UnknownError: + qDebug() << "Unknown process error."; + break; + } +} diff --git a/tests/auto/qml/debugger/shared/qqmldebugprocess_p.h b/tests/auto/qml/debugger/shared/qqmldebugprocess_p.h new file mode 100644 index 0000000000..fd2c89bb41 --- /dev/null +++ b/tests/auto/qml/debugger/shared/qqmldebugprocess_p.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Copyright (C) 2017 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 QQMLDEBUGPROCESS_P_H +#define QQMLDEBUGPROCESS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtCore/qprocess.h> +#include <QtCore/qtimer.h> +#include <QtCore/qeventloop.h> +#include <QtCore/qmutex.h> + +class QQmlDebugProcess : public QObject +{ + Q_OBJECT +public: + QQmlDebugProcess(const QString &executable, QObject *parent = 0); + ~QQmlDebugProcess(); + + QString state(); + + void addEnvironment(const QString &environment); + + void start(const QStringList &arguments); + bool waitForSessionStart(); + int debugPort() const; + + bool waitForFinished(); + QProcess::ExitStatus exitStatus() const; + + QString output() const; + void stop(); + void setMaximumBindErrors(int numErrors); + +signals: + void readyReadStandardOutput(); + +private slots: + void timeout(); + void processAppOutput(); + void processError(QProcess::ProcessError error); + +private: + enum SessionState { + SessionUnknown, + SessionStarted, + SessionFailed + }; + + QString m_executable; + QProcess m_process; + QString m_outputBuffer; + QString m_output; + QTimer m_timer; + QEventLoop m_eventLoop; + QMutex m_mutex; + SessionState m_state; + QStringList m_environment; + int m_port; + int m_maximumBindErrors; + int m_receivedBindErrors; +}; + +#endif // QQMLDEBUGPROCESS_P_H diff --git a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp index c0252a0290..7e736ec400 100644 --- a/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp +++ b/tests/auto/qml/debugger/shared/qqmlenginedebugclient.cpp @@ -385,7 +385,7 @@ void QQmlEngineDebugClient::decode(QPacket &ds, case QmlObjectProperty::Object: { QmlDebugObjectReference obj; - obj.debugId = prop.value.toInt(); + obj.name = data.value.toString(); obj.className = prop.valueTypeName; prop.value = qVariantFromValue(obj); break; diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index 49f107452a..589f25d174 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -15,7 +15,6 @@ S15.1.2.3_A2_T10 15.5.4.20-3-5 15.5.4.20-3-6 -10.4.3-1-106 failing 11.2.3-3_3 failing S13_A15_T4 failing S15.4.4.3_A1_T1 failing @@ -29,3 +28,150 @@ Sbp_12.5_A9_T3 failing Sbp_12.6.1_A13_T3 failing Sbp_12.6.2_A13_T3 failing Sbp_12.6.4_A13_T3 failing + +# es6: function length attributes are configurable, wasn't in es5 +S15.1.2.2_A9.2 failing +S15.1.3.1_A5.2 failing +S15.1.3.2_A5.2 failing +S15.1.3.3_A5.2 failing +S15.1.2.3_A7.2 failing +S15.1.2.4_A2.2 failing +S15.1.2.5_A2.2 failing +S15.1.3.4_A5.2 failing +15.2.3.3-4-186 failing +S15.2.4.2_A9 failing +S15.2.4.3_A9 failing +S15.2.4.4_A9 failing +S15.2.4.5_A9 failing +S15.2.4.6_A9 failing +S15.2.4.7_A9 failing +15.3.3.2-1 failing +15.4.4.2_A4.2 +S15.3.4.2_A9 failing +S15.3.4.3_A9 failing +S15.3.4.4_A9 failing +15.3.4.5-15-2 failing +S15.4.4.2_A4.2 failing +S15.4.4.3_A4.2 failing +S15.4.4.4_A4.2 failing +S15.4.4.5_A6.2 failing +S15.4.4.6_A5.2 failing +S15.4.4.7_A6.2 failing +S15.4.4.8_A5.2 failing +S15.4.4.9_A5.2 failing +S15.4.4.10_A5.2 failing +S15.4.4.11_A7.2 failing +S15.4.4.12_A5.2 failing +S15.4.4.13_A5.2 failing +S15.5.4.10_A9 failing +S15.5.4.11_A9 failing +S15.5.4.12_A9 failing +S15.5.4.13_A9 failing +S15.5.4.14_A9 failing +S15.5.4.15_A9 failing +S15.5.4.16_A9 failing +S15.5.4.17_A9 failing +S15.5.4.18_A9 failing +S15.5.4.19_A9 failing +S15.5.4.4_A9 failing +S15.5.4.5_A9 failing +S15.5.4.6_A9 failing +S15.5.4.7_A9 failing +S15.5.4.8_A9 failing +S15.5.4.9_A9 failing +S15.9.4.2_A3_T2 failing +S15.9.4.3_A3_T2 failing +S15.9.5.2_A3_T2 failing +S15.9.5.3_A3_T2 failing +S15.9.5.4_A3_T2 failing +S15.9.5.5_A3_T2 failing +S15.9.5.1_A3_T2 failing +S15.9.5.10_A3_T2 failing +S15.9.5.11_A3_T2 failing +S15.9.5.12_A3_T2 failing +S15.9.5.13_A3_T2 failing +S15.9.5.14_A3_T2 failing +S15.9.5.15_A3_T2 failing +S15.9.5.16_A3_T2 failing +S15.9.5.17_A3_T2 failing +S15.9.5.18_A3_T2 failing +S15.9.5.19_A3_T2 failing +S15.9.5.20_A3_T2 failing +S15.9.5.21_A3_T2 failing +S15.9.5.22_A3_T2 failing +S15.9.5.23_A3_T2 failing +S15.9.5.24_A3_T2 failing +S15.9.5.25_A3_T2 failing +S15.9.5.26_A3_T2 failing +S15.9.5.27_A3_T2 failing +S15.9.5.28_A3_T2 failing +S15.9.5.29_A3_T2 failing +S15.9.5.30_A3_T2 failing +S15.9.5.31_A3_T2 failing +S15.9.5.32_A3_T2 failing +S15.9.5.33_A3_T2 failing +S15.9.5.34_A3_T2 failing +S15.9.5.35_A3_T2 failing +S15.9.5.36_A3_T2 failing +S15.9.5.37_A3_T2 failing +S15.9.5.38_A3_T2 failing +S15.9.5.39_A3_T2 failing +S15.9.5.40_A3_T2 failing +S15.9.5.41_A3_T2 failing +S15.9.5.42_A3_T2 failing +S15.9.5.6_A3_T2 failing +S15.9.5.7_A3_T2 failing +S15.9.5.8_A3_T2 failing +S15.9.5.9_A3_T2 failing +S15.10.6.2_A9 failing +S15.10.6.3_A9 failing +S15.10.6.4_A9 failing + +# es6: Object.freeze(v) on a non-object returns v, no longer TypeError +15.2.3.9-1 failing +15.2.3.9-1-1 failing +15.2.3.9-1-2 failing +15.2.3.9-1-3 failing +15.2.3.9-1-4 failing +# es6: Object.preventExtensions(O) on a non-object, no longer TypeError +15.2.3.10-1 failing +15.2.3.10-1-3 failing +15.2.3.10-1-4 failing +# es6: Object.isSealed(O) on a non-object, no longer TypeError +15.2.3.11-1 +# es6: Object.isFrozen(O) on a non-object, no longer TypeError +15.2.3.12-1 +15.2.3.12-1-3 +15.2.3.12-1-4 +# es6: Object.isExtensible(O) on a non-object, no longer TypeError +15.2.3.13-1 +15.2.3.13-1-3 +15.2.3.13-1-4 +# es6: Object.keys(O) on a non-object, no longer TypeError +15.2.3.14-1-1 +15.2.3.14-1-2 +15.2.3.14-1-3 +15.2.3.14-1 +15.2.3.14-2 +15.2.3.14-3 +# es6: Object.getOwnPropertyDescriptor(O) on a non-object, no longer TypeError +15.2.3.3-1 +15.2.3.3-1-3 +15.2.3.3-1-4 +# es6: Object.getPrototypeOf(O) on a non-object, no longer TypeError +15.2.3.2-1 +15.2.3.2-1-3 +15.2.3.2-1-4 +# es6: Object.getOwnPropertyNames(O) on a non-object, no longer TypeError +15.2.3.4-1 +15.2.3.4-1-4 +15.2.3.4-1-5 +# es6: Object.seal(O) on a non-object, no longer TypeError +15.2.3.8-1 +15.2.3.8-1-1 +15.2.3.8-1-2 +15.2.3.8-1-3 +15.2.3.8-1-4 + +# es6: Date.prototype is no longer a DateObject +15.9.5.40_1 failing diff --git a/tests/auto/qml/ecmascripttests/test262 b/tests/auto/qml/ecmascripttests/test262 -Subproject fe58b18c13d1ea5d42951e5b698efc3bfab6dc8 +Subproject d60c4ed97e69639bc5bc1db43a98828debf80c8 diff --git a/tests/auto/qml/ecmascripttests/test262.py b/tests/auto/qml/ecmascripttests/test262.py index 437cd1b27d..ae4c54df9d 100755 --- a/tests/auto/qml/ecmascripttests/test262.py +++ b/tests/auto/qml/ecmascripttests/test262.py @@ -552,10 +552,10 @@ class TestSuite(object): def Main(): - # Some date tests rely on being run in pacific time. # Uncomment the next line for more logging info. #logging.basicConfig(level=logging.DEBUG) - os.environ["TZ"] = "PST8PDT" + # Some date tests rely on being run in pacific time and the USA's locale: + os.environ["TZ"] = "America/Vancouver" os.environ["LANG"] = "en_US.UTF-8" os.environ["LC_TIME"] = "en_US.UTF-8" parser = BuildOptions() diff --git a/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp b/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp index 880e254543..0d58d045b9 100644 --- a/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp +++ b/tests/auto/qml/ecmascripttests/tst_ecmascripttests.cpp @@ -34,29 +34,29 @@ class tst_EcmaScriptTests : public QObject { Q_OBJECT -private slots: - void runTests_data(); - void runTests(); -}; -void tst_EcmaScriptTests::runTests_data() -{ - QTest::addColumn<QString>("qmljsParameter"); + void runTests(bool interpret); - QTest::newRow("jit") << QStringLiteral("--jit"); - QTest::newRow("interpreter") << QStringLiteral("--interpret"); -} +private slots: + void runInterpreted(); + void runJitted(); +}; -void tst_EcmaScriptTests::runTests() +void tst_EcmaScriptTests::runTests(bool interpret) { #if defined(Q_OS_LINUX) && defined(Q_PROCESSOR_X86_64) - QFETCH(QString, qmljsParameter); + QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); + if (interpret) + env.insert("QV4_FORCE_INTERPRETER", "1"); + else + env.insert("QV4_JIT_CALL_THRESHOLD", "0"); QProcess process; process.setProcessChannelMode(QProcess::ForwardedChannels); process.setWorkingDirectory(QLatin1String(SRCDIR)); process.setProgram("python"); - process.setArguments(QStringList() << "test262.py" << "--command=" + QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs " + qmljsParameter << "--parallel" << "--with-test-expectations"); + process.setProcessEnvironment(env); + process.setArguments(QStringList() << "test262.py" << "--command=" + QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qmljs" << "--parallel" << "--with-test-expectations"); qDebug() << "Going to run" << process.program() << process.arguments() << "in" << process.workingDirectory(); @@ -71,6 +71,16 @@ void tst_EcmaScriptTests::runTests() #endif } +void tst_EcmaScriptTests::runInterpreted() +{ + runTests(true); +} + +void tst_EcmaScriptTests::runJitted() +{ + runTests(false); +} + QTEST_GUILESS_MAIN(tst_EcmaScriptTests) #include "tst_ecmascripttests.moc" diff --git a/tests/auto/qml/qjsengine/tst_qjsengine.cpp b/tests/auto/qml/qjsengine/tst_qjsengine.cpp index 8b815f7a06..519c57efb2 100644 --- a/tests/auto/qml/qjsengine/tst_qjsengine.cpp +++ b/tests/auto/qml/qjsengine/tst_qjsengine.cpp @@ -201,6 +201,8 @@ private slots: void malformedExpression(); + void scriptScopes(); + signals: void testSignal(); }; @@ -569,10 +571,6 @@ void tst_QJSEngine::newDate() QCOMPARE(date.isDate(), true); QCOMPARE(date.isObject(), true); QVERIFY(!date.isCallable()); - // prototype should be Date.prototype - QVERIFY(!date.prototype().isUndefined()); - QCOMPARE(date.prototype().isDate(), true); - QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true); } { @@ -581,10 +579,6 @@ void tst_QJSEngine::newDate() QVERIFY(!date.isUndefined()); QCOMPARE(date.isDate(), true); QCOMPARE(date.isObject(), true); - // prototype should be Date.prototype - QVERIFY(!date.prototype().isUndefined()); - QCOMPARE(date.prototype().isDate(), true); - QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true); QCOMPARE(date.toDateTime(), dt); } @@ -1115,7 +1109,7 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("Date.prototype.setFullYear") << QString("Date.prototype.setFullYear") << QString("setFullYear"); QTest::newRow("Date.prototype.setUTCFullYear") << QString("Date.prototype.setUTCFullYear") << QString("setUTCFullYear"); QTest::newRow("Date.prototype.toUTCString") << QString("Date.prototype.toUTCString") << QString("toUTCString"); - QTest::newRow("Date.prototype.toGMTString") << QString("Date.prototype.toGMTString") << QString("toGMTString"); + QTest::newRow("Date.prototype.toGMTString") << QString("Date.prototype.toGMTString") << QString("toUTCString"); // yes, this is per spec QTest::newRow("Error") << QString("Error") << QString("Error"); // QTest::newRow("Error.prototype.backtrace") << QString("Error.prototype.backtrace") << QString("backtrace"); @@ -1193,6 +1187,7 @@ void tst_QJSEngine::builtinFunctionNames_data() QTest::newRow("String.prototype.lastIndexOf") << QString("String.prototype.lastIndexOf") << QString("lastIndexOf"); QTest::newRow("String.prototype.localeCompare") << QString("String.prototype.localeCompare") << QString("localeCompare"); QTest::newRow("String.prototype.match") << QString("String.prototype.match") << QString("match"); + QTest::newRow("String.prototype.repeat") << QString("String.prototype.repeat") << QString("repeat"); QTest::newRow("String.prototype.replace") << QString("String.prototype.replace") << QString("replace"); QTest::newRow("String.prototype.search") << QString("String.prototype.search") << QString("search"); QTest::newRow("String.prototype.slice") << QString("String.prototype.slice") << QString("slice"); @@ -4125,6 +4120,22 @@ void tst_QJSEngine::malformedExpression() engine.evaluate("5%55555&&5555555\n7-0"); } +void tst_QJSEngine::scriptScopes() +{ + QJSEngine engine; + + QJSValue def = engine.evaluate("'use strict'; function foo() { return 42 }"); + QVERIFY(!def.isError()); + QJSValue globalObject = engine.globalObject(); + QJSValue foo = globalObject.property("foo"); + QVERIFY(foo.isObject()); + QVERIFY(foo.isCallable()); + + QJSValue use = engine.evaluate("'use strict'; foo()"); + QVERIFY(use.isNumber()); + QCOMPARE(use.toInt(), 42); +} + QTEST_MAIN(tst_QJSEngine) #include "tst_qjsengine.moc" diff --git a/tests/auto/qml/qjsonbinding/qjsonbinding.pro b/tests/auto/qml/qjsonbinding/qjsonbinding.pro index 75b48aa854..f7a185d27a 100644 --- a/tests/auto/qml/qjsonbinding/qjsonbinding.pro +++ b/tests/auto/qml/qjsonbinding/qjsonbinding.pro @@ -3,7 +3,6 @@ TARGET = tst_qjsonbinding macx:CONFIG -= app_bundle SOURCES += tst_qjsonbinding.cpp -INCLUDEPATH += ../../shared include (../../shared/util.pri) diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp index 12c33909cf..db99c44261 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp @@ -970,10 +970,6 @@ void tst_QJSValue::toUInt() QCOMPARE(qjsvalue_cast<quint32>(inv), quint32(0)); } -#if defined Q_CC_MSVC && _MSC_VER < 1300 -Q_DECLARE_METATYPE(QVariant) -#endif - void tst_QJSValue::toVariant() { QJSEngine eng; diff --git a/tests/auto/qml/qml.pro b/tests/auto/qml/qml.pro index 42a5400dc1..9557393a2e 100644 --- a/tests/auto/qml/qml.pro +++ b/tests/auto/qml/qml.pro @@ -1,4 +1,5 @@ TEMPLATE = subdirs +QT_FOR_CONFIG += qml METATYPETESTS += \ qqmlmetatype @@ -10,7 +11,6 @@ PUBLICTESTS += \ qqmlfile \ qqmlfileselector -!boot2qt { PUBLICTESTS += \ qmlmin \ qqmlcomponent \ @@ -32,15 +32,12 @@ PUBLICTESTS += \ qqmlsettings \ qqmlstatemachine \ qmldiskcache -} PRIVATETESTS += \ qqmlcpputils \ qqmldirparser \ - v4misc \ qmlcachegen -!boot2qt { PRIVATETESTS += \ animation \ qqmlecmascript \ @@ -73,20 +70,23 @@ PRIVATETESTS += \ qqmlimport \ qqmlobjectmodel \ qv4mm \ - ecmascripttests -} + ecmascripttests \ + bindingdependencyapi qtHaveModule(widgets) { PUBLICTESTS += \ qjsengine \ - qjsvalue + qjsvalue \ +# qwidgetsinqml } SUBDIRS += $$PUBLICTESTS SUBDIRS += $$METATYPETESTS -qtConfig(process):!boot2qt { - !contains(QT_CONFIG, no-qml-debug): SUBDIRS += debugger - SUBDIRS += qmllint qmlplugindump +qtConfig(process) { + qtConfig(qml-debug): SUBDIRS += debugger + !boot2qt { + SUBDIRS += qmllint qmlplugindump + } } qtConfig(library) { diff --git a/tests/auto/qml/qmlcachegen/qmlcachegen.pro b/tests/auto/qml/qmlcachegen/qmlcachegen.pro index 8d8b37be15..a8b72224ba 100644 --- a/tests/auto/qml/qmlcachegen/qmlcachegen.pro +++ b/tests/auto/qml/qmlcachegen/qmlcachegen.pro @@ -1,7 +1,11 @@ -CONFIG += testcase +CONFIG += testcase qtquickcompiler TARGET = tst_qmlcachegen macos:CONFIG -= app_bundle SOURCES += tst_qmlcachegen.cpp +workerscripts_test.files = worker.js worker.qml +workerscripts_test.prefix = /workerscripts +RESOURCES += workerscripts_test + QT += core-private qml-private testlib diff --git a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp index 98a3a9d6ef..2f5ff0022e 100644 --- a/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp +++ b/tests/auto/qml/qmlcachegen/tst_qmlcachegen.cpp @@ -44,7 +44,11 @@ private slots: void loadGeneratedFile(); void translationExpressionSupport(); + void signalHandlerParameters(); void errorOnArgumentsInSignalHandler(); + void aheadOfTimeCompilation(); + + void workerScripts(); }; // A wrapper around QQmlComponent to ensure the temporary reference counts @@ -75,7 +79,7 @@ static bool generateCache(const QString &qmlFileName, QByteArray *capturedStderr if (capturedStderr == nullptr) proc.setProcessChannelMode(QProcess::ForwardedChannels); proc.setProgram(QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator() + QLatin1String("qmlcachegen")); - proc.setArguments(QStringList() << (QLatin1String("--target-architecture=") + QSysInfo::buildCpuArchitecture()) << (QLatin1String("--target-abi=") + QSysInfo::buildAbi()) << qmlFileName); + proc.setArguments(QStringList() << qmlFileName); proc.start(); if (!proc.waitForFinished()) return false; @@ -182,6 +186,41 @@ void tst_qmlcachegen::translationExpressionSupport() QCOMPARE(obj->property("text").toString(), QString("All Ok")); } +void tst_qmlcachegen::signalHandlerParameters() +{ + QTemporaryDir tempDir; + QVERIFY(tempDir.isValid()); + + const auto writeTempFile = [&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(); + }; + + const QString testFilePath = writeTempFile("test.qml", "import QtQml 2.0\n" + "QtObject {\n" + " property real result: 0\n" + " signal testMe(real value);\n" + " onTestMe: result = value;\n" + " function runTest() { testMe(42); }\n" + "}"); + + QVERIFY(generateCache(testFilePath)); + + const QString cacheFilePath = testFilePath + QLatin1Char('c'); + QVERIFY(QFile::exists(cacheFilePath)); + QVERIFY(QFile::remove(testFilePath)); + + QQmlEngine engine; + CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath)); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QMetaObject::invokeMethod(obj.data(), "runTest"); + QCOMPARE(obj->property("result").toInt(), 42); +} + void tst_qmlcachegen::errorOnArgumentsInSignalHandler() { QTemporaryDir tempDir; @@ -207,6 +246,52 @@ void tst_qmlcachegen::errorOnArgumentsInSignalHandler() QVERIFY2(errorOutput.contains("error: The use of the arguments object in signal handlers is"), errorOutput); } +void tst_qmlcachegen::aheadOfTimeCompilation() +{ + QTemporaryDir tempDir; + QVERIFY(tempDir.isValid()); + + const auto writeTempFile = [&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(); + }; + + const QString testFilePath = writeTempFile("test.qml", "import QtQml 2.0\n" + "QtObject {\n" + " function runTest() { var x = 0; while (x < 42) { ++x }; return x; }\n" + "}"); + + QVERIFY(generateCache(testFilePath)); + + const QString cacheFilePath = testFilePath + QLatin1Char('c'); + QVERIFY(QFile::exists(cacheFilePath)); + QVERIFY(QFile::remove(testFilePath)); + + QQmlEngine engine; + CleanlyLoadingComponent component(&engine, QUrl::fromLocalFile(testFilePath)); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QVariant result; + QMetaObject::invokeMethod(obj.data(), "runTest", Q_RETURN_ARG(QVariant, result)); + QCOMPARE(result.toInt(), 42); +} + +void tst_qmlcachegen::workerScripts() +{ + QVERIFY(QFile::exists(":/workerscripts/worker.js")); + QVERIFY(QFile::exists(":/workerscripts/worker.qml")); + QCOMPARE(QFileInfo(":/workerscripts/worker.js").size(), 0); + + QQmlEngine engine; + CleanlyLoadingComponent component(&engine, QUrl("qrc:///workerscripts/worker.qml")); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QTRY_VERIFY(obj->property("success").toBool()); +} + QTEST_GUILESS_MAIN(tst_qmlcachegen) #include "tst_qmlcachegen.moc" diff --git a/tests/auto/qml/qmlcachegen/worker.js b/tests/auto/qml/qmlcachegen/worker.js new file mode 100644 index 0000000000..dd2d0b843d --- /dev/null +++ b/tests/auto/qml/qmlcachegen/worker.js @@ -0,0 +1,3 @@ +WorkerScript.onMessage = function(message) { + WorkerScript.sendMessage({ reply: message }); +} diff --git a/tests/auto/qml/qmlcachegen/worker.qml b/tests/auto/qml/qmlcachegen/worker.qml new file mode 100644 index 0000000000..1f1c9d1ac7 --- /dev/null +++ b/tests/auto/qml/qmlcachegen/worker.qml @@ -0,0 +1,12 @@ +import QtQml 2.0 +import QtQuick 2.0 +QtObject { + property bool success: false + property WorkerScript worker: WorkerScript { + source: "worker.js" + onMessage: { + success = true + } + } + Component.onCompleted: worker.sendMessage("Hello") +} diff --git a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp index e75e51ed29..f5905758f3 100644 --- a/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp +++ b/tests/auto/qml/qmldiskcache/tst_qmldiskcache.cpp @@ -30,10 +30,9 @@ #include <private/qv4compileddata_p.h> #include <private/qv4compiler_p.h> -#include <private/qv4jsir_p.h> -#include <private/qv4isel_p.h> #include <private/qv8engine_p.h> #include <private/qv4engine_p.h> +#include <private/qv4codegen_p.h> #include <QQmlComponent> #include <QQmlEngine> #include <QQmlFileSelector> @@ -174,9 +173,8 @@ struct TestCompiler bool verify() { - QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); - QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = v4->iselFactory->createUnitForLoading(); - return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), QFileInfo(testFilePath).lastModified(), v4->iselFactory.data(), &lastErrorString); + QQmlRefPointer<QV4::CompiledData::CompilationUnit> unit = QV4::Compiler::Codegen::createUnitForLoading(); + return unit->loadFromDisk(QUrl::fromLocalFile(testFilePath), QFileInfo(testFilePath).lastModified(), &lastErrorString); } void closeMapping() @@ -231,12 +229,14 @@ void tst_qmldiskcache::regenerateAfterChange() const QV4::CompiledData::Object *obj = testUnit->objectAt(0); QCOMPARE(quint32(obj->nBindings), quint32(1)); QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Script)); - QCOMPARE(quint32(obj->bindingTable()->value.compiledScriptIndex), quint32(1)); + QCOMPARE(quint32(obj->bindingTable()->value.compiledScriptIndex), quint32(0)); - QCOMPARE(quint32(testUnit->functionTableSize), quint32(2)); + QCOMPARE(quint32(testUnit->functionTableSize), quint32(1)); - const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1); - QVERIFY(bindingFunction->codeOffset > testUnit->unitSize); + const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(0); + QCOMPARE(testUnit->stringAt(bindingFunction->nameIndex), QString("expression for blah")); // check if we have the correct function + QVERIFY(bindingFunction->codeSize > 0); + QVERIFY(bindingFunction->codeOffset < testUnit->unitSize); } { @@ -257,10 +257,12 @@ void tst_qmldiskcache::regenerateAfterChange() QCOMPARE(quint32(obj->bindingTable()->type), quint32(QV4::CompiledData::Binding::Type_Number)); QCOMPARE(obj->bindingTable()->valueAsNumber(), double(42)); - QCOMPARE(quint32(testUnit->functionTableSize), quint32(2)); + QCOMPARE(quint32(testUnit->functionTableSize), quint32(1)); - const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(1); - QVERIFY(bindingFunction->codeOffset > testUnit->unitSize); + const QV4::CompiledData::Function *bindingFunction = testUnit->functionAt(0); + QCOMPARE(testUnit->stringAt(bindingFunction->nameIndex), QString("expression for blah")); // check if we have the correct function + QVERIFY(bindingFunction->codeSize > 0); + QVERIFY(bindingFunction->codeOffset < testUnit->unitSize); } } @@ -342,30 +344,6 @@ void tst_qmldiskcache::basicVersionChecks() QVERIFY(!testCompiler.verify()); QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("V4 data structure version mismatch. Found 0 expected %1").arg(QV4_DATA_STRUCTURE_VERSION, 0, 16)); } - - { - testCompiler.clearCache(); - QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); - - testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { - header->architectureIndex = 0; - }); - - QVERIFY(!testCompiler.verify()); - QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Architecture mismatch. Found expected %1").arg(QSysInfo::buildAbi())); - } - - { - testCompiler.clearCache(); - QVERIFY2(testCompiler.compile(contents), qPrintable(testCompiler.lastErrorString)); - - testCompiler.tweakHeader([](QV4::CompiledData::Unit *header) { - header->codeGeneratorIndex = 0; - }); - - QVERIFY(!testCompiler.verify()); - QCOMPARE(testCompiler.lastErrorString, QString::fromUtf8("Code generator mismatch. Found code generated by but expected %1").arg(QV8Engine::getV4(&engine)->iselFactory->codeGeneratorName)); - } } class TypeVersion1 : public QObject diff --git a/tests/auto/qml/qmlmin/qmlmin.pro b/tests/auto/qml/qmlmin/qmlmin.pro index 6af6653270..93e5caabcf 100644 --- a/tests/auto/qml/qmlmin/qmlmin.pro +++ b/tests/auto/qml/qmlmin/qmlmin.pro @@ -6,5 +6,7 @@ macx:CONFIG -= app_bundle SOURCES += tst_qmlmin.cpp DEFINES += SRCDIR=\\\"$$PWD\\\" - -cross_compile: DEFINES += QTEST_CROSS_COMPILED +# Boot2qt is cross compiled but it has sources available +!boot2qt { + cross_compile: DEFINES += QTEST_CROSS_COMPILED +} diff --git a/tests/auto/qml/qmlmin/tst_qmlmin.cpp b/tests/auto/qml/qmlmin/tst_qmlmin.cpp index 171c2bda8a..5941385c80 100644 --- a/tests/auto/qml/qmlmin/tst_qmlmin.cpp +++ b/tests/auto/qml/qmlmin/tst_qmlmin.cpp @@ -98,6 +98,8 @@ void tst_qmlmin::initTestCase() invalidFiles << "tests/auto/qml/qqmllanguage/data/insertedSemicolon.1.qml"; invalidFiles << "tests/auto/qml/qqmllanguage/data/nonexistantProperty.5.qml"; invalidFiles << "tests/auto/qml/qqmllanguage/data/invalidRoot.1.qml"; + invalidFiles << "tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.qml"; + invalidFiles << "tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.qml"; invalidFiles << "tests/auto/qml/qquickfolderlistmodel/data/dummy.qml"; invalidFiles << "tests/auto/qml/qqmlecmascript/data/qtbug_22843.js"; invalidFiles << "tests/auto/qml/qqmlecmascript/data/qtbug_22843.library.js"; diff --git a/tests/auto/qml/qmlplugindump/tests/dumper/CompositeSingleton/Singleton.qml b/tests/auto/qml/qmlplugindump/data/dumper/CompositeSingleton/Singleton.qml index b47d2e98f4..b47d2e98f4 100644 --- a/tests/auto/qml/qmlplugindump/tests/dumper/CompositeSingleton/Singleton.qml +++ b/tests/auto/qml/qmlplugindump/data/dumper/CompositeSingleton/Singleton.qml diff --git a/tests/auto/qml/qmlplugindump/tests/dumper/CompositeSingleton/qmldir b/tests/auto/qml/qmlplugindump/data/dumper/CompositeSingleton/qmldir index 8df57f6d47..8df57f6d47 100644 --- a/tests/auto/qml/qmlplugindump/tests/dumper/CompositeSingleton/qmldir +++ b/tests/auto/qml/qmlplugindump/data/dumper/CompositeSingleton/qmldir diff --git a/tests/auto/qml/qmlplugindump/qmlplugindump.pro b/tests/auto/qml/qmlplugindump/qmlplugindump.pro index 9327beffa6..ab915c819c 100644 --- a/tests/auto/qml/qmlplugindump/qmlplugindump.pro +++ b/tests/auto/qml/qmlplugindump/qmlplugindump.pro @@ -1,7 +1,7 @@ -CONFIG += testcase -TARGET = tst_qmlplugindump -QT += testlib gui-private +QT += testlib gui-private qml macx:CONFIG -= app_bundle +include(../../shared/util.pri) + DEFINES += QT_QMLTEST_DIR=\\\"$${_PRO_FILE_PWD_}\\\" SOURCES += tst_qmlplugindump.cpp diff --git a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp index 235cf6fac9..ffddc52f9c 100644 --- a/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp +++ b/tests/auto/qml/qmlplugindump/tst_qmlplugindump.cpp @@ -26,6 +26,8 @@ ** ****************************************************************************/ +#include "util.h" + #include <qtest.h> #include <QLibraryInfo> #include <QDir> @@ -33,7 +35,7 @@ #include <QDebug> #include <cstdlib> -class tst_qmlplugindump : public QObject +class tst_qmlplugindump : public QQmlDataTest { Q_OBJECT public: @@ -54,6 +56,7 @@ tst_qmlplugindump::tst_qmlplugindump() void tst_qmlplugindump::initTestCase() { + QQmlDataTest::initTestCase(); qmlplugindumpPath = QLibraryInfo::location(QLibraryInfo::BinariesPath); #if defined(Q_OS_WIN) @@ -105,12 +108,12 @@ void tst_qmlplugindump::singleton() args << QLatin1String("tests.dumper.CompositeSingleton") << QLatin1String("1.0") << QLatin1String(QT_QMLTEST_DIR); dumper.start(qmlplugindumpPath, args); - dumper.waitForFinished(); + QVERIFY2(dumper.waitForStarted(), qPrintable(dumper.errorString())); + QVERIFY2(dumper.waitForFinished(), qPrintable(dumper.errorString())); const QString &result = dumper.readAllStandardOutput(); - qDebug() << "result: " << result; - QVERIFY(result.contains(QLatin1String("exports: [\"Singleton 1.0\"]"))); - QVERIFY(result.contains(QLatin1String("exportMetaObjectRevisions: [0]"))); + QVERIFY2(result.contains(QLatin1String("exports: [\"Singleton 1.0\"]")), qPrintable(result)); + QVERIFY2(result.contains(QLatin1String("exportMetaObjectRevisions: [0]")), qPrintable(result)); } QTEST_MAIN(tst_qmlplugindump) diff --git a/tests/auto/qml/qqmlapplicationengine/qqmlapplicationengine.pro b/tests/auto/qml/qqmlapplicationengine/qqmlapplicationengine.pro index 4a2dde7c47..3adad3759b 100644 --- a/tests/auto/qml/qqmlapplicationengine/qqmlapplicationengine.pro +++ b/tests/auto/qml/qqmlapplicationengine/qqmlapplicationengine.pro @@ -1,3 +1,5 @@ TEMPLATE = subdirs -SUBDIRS = tst_qqmlapplicationengine.pro \ - testapp +SUBDIRS = testapp \ + tst_qqmlapplicationengine.pro + +CONFIG += ordered diff --git a/tests/auto/qml/qqmlbinding/data/bindingOverwriting.qml b/tests/auto/qml/qqmlbinding/data/bindingOverwriting.qml new file mode 100644 index 0000000000..767ca0c719 --- /dev/null +++ b/tests/auto/qml/qqmlbinding/data/bindingOverwriting.qml @@ -0,0 +1,13 @@ +import QtQuick 2.9 + +Text { + visible: text && enabled + enabled: font.pixelSize === 25 + font: enabled ? Qt.font({ "pixelSize": 25 }) : Qt.font({ "pixelSize": 50 }) + + Component.onCompleted: { + enabled = Qt.binding(function() { return visible; }); // replacement binding, not breaking + visible = true; // breaks visible binding + font.bold = true; // breaks font binding + } +} diff --git a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp index 6f1d82eca5..4b485d2ce8 100644 --- a/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp +++ b/tests/auto/qml/qqmlbinding/tst_qqmlbinding.cpp @@ -50,6 +50,7 @@ private slots: void disabledOnUnknownProperty(); void disabledOnReadonlyProperty(); void delayed(); + void bindingOverwriting(); private: QQmlEngine engine; @@ -303,6 +304,21 @@ void tst_qqmlbinding::delayed() delete item; } +void tst_qqmlbinding::bindingOverwriting() +{ + QQmlTestMessageHandler messageHandler; + QLoggingCategory::setFilterRules(QStringLiteral("qt.qml.binding.removal.info=true")); + + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("bindingOverwriting.qml")); + QQuickItem *item = qobject_cast<QQuickItem*>(c.create()); + QVERIFY(item); + delete item; + + QLoggingCategory::setFilterRules(QString()); + QCOMPARE(messageHandler.messages().count(), 2); +} + QTEST_MAIN(tst_qqmlbinding) #include "tst_qqmlbinding.moc" diff --git a/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp b/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp index da7956a5fb..f12c3432c2 100644 --- a/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp +++ b/tests/auto/qml/qqmlchangeset/tst_qqmlchangeset.cpp @@ -26,6 +26,7 @@ ** ****************************************************************************/ #include <qtest.h> +#include <qrandom.h> #include <private/qqmlchangeset_p.h> class tst_qqmlchangeset : public QObject @@ -1462,23 +1463,19 @@ void tst_qqmlchangeset::debug() void tst_qqmlchangeset::random_data() { - QTest::addColumn<int>("seed"); QTest::addColumn<int>("combinations"); QTest::addColumn<int>("depth"); - QTest::newRow("1*5") << 32 << 1 << 5; - QTest::newRow("2*2") << 32 << 2 << 2; - QTest::newRow("3*2") << 32 << 3 << 2; - QTest::newRow("3*5") << 32 << 3 << 5; + QTest::newRow("1*5") << 1 << 5; + QTest::newRow("2*2") << 2 << 2; + QTest::newRow("3*2") << 3 << 2; + QTest::newRow("3*5") << 3 << 5; } void tst_qqmlchangeset::random() { - QFETCH(int, seed); QFETCH(int, combinations); QFETCH(int, depth); - qsrand(seed); - int failures = 0; for (int i = 0; i < 20000; ++i) { QQmlChangeSet accumulatedSet; @@ -1490,27 +1487,27 @@ void tst_qqmlchangeset::random() for (int j = 0; j < combinations; ++j) { QQmlChangeSet set; for (int k = 0; k < depth; ++k) { - switch (-(qrand() % 3)) { + switch (-QRandomGenerator::global()->bounded(3)) { case InsertOp: { - int index = qrand() % (modelCount + 1); - int count = qrand() % 5 + 1; + int index = QRandomGenerator::global()->bounded(modelCount + 1); + int count = QRandomGenerator::global()->bounded(5) + 1; set.insert(index, count); input.append(Insert(index, count)); modelCount += count; break; } case RemoveOp: { - const int index = qrand() % (modelCount + 1); - const int count = qrand() % (modelCount - index + 1); + const int index = QRandomGenerator::global()->bounded(modelCount + 1); + const int count = QRandomGenerator::global()->bounded(modelCount - index + 1); set.remove(index, count); input.append(Remove(index, count)); modelCount -= count; break; } case MoveOp: { - const int from = qrand() % (modelCount + 1); - const int count = qrand() % (modelCount - from + 1); - const int to = qrand() % (modelCount - count + 1); + const int from = QRandomGenerator::global()->bounded(modelCount + 1); + const int count = QRandomGenerator::global()->bounded(modelCount - from + 1); + const int to = QRandomGenerator::global()->bounded(modelCount - count + 1); const int moveId = moveCount++; set.move(from, to, count, moveId); input.append(Move(from, to, count, moveId)); diff --git a/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro b/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro index 0d501ebefd..54012e050c 100644 --- a/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro +++ b/tests/auto/qml/qqmlcomponent/qqmlcomponent.pro @@ -2,7 +2,6 @@ CONFIG += testcase TARGET = tst_qqmlcomponent macx:CONFIG -= app_bundle -INCLUDEPATH += ../../shared/ SOURCES += tst_qqmlcomponent.cpp \ ../../shared/testhttpserver.cpp diff --git a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp index 3c78f6601e..105469fbcf 100644 --- a/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp +++ b/tests/auto/qml/qqmlcomponent/tst_qqmlcomponent.cpp @@ -544,7 +544,7 @@ public: QJSEngine *jsEngine = qjsEngine(this); if (!jsEngine) return; - QV4::ExecutionEngine *v4 = QV8Engine::getV4(jsEngine); + QV4::ExecutionEngine *v4 = jsEngine->handle(); if (!v4) return; QV4::Scope scope(v4); diff --git a/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml b/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml new file mode 100644 index 0000000000..462a9577ff --- /dev/null +++ b/tests/auto/qml/qqmlconnections/data/connection-no-signal-name.qml @@ -0,0 +1,15 @@ +import QtQuick 2.4 + +Item { + id: blaBlaBla + function hint() { + } + + Connections { + //target: blaBlaBla + //onHint: hint(); + on: true + } +} + + diff --git a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp index fe45495f74..22e9724c61 100644 --- a/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp +++ b/tests/auto/qml/qqmlconnections/tst_qqmlconnections.cpp @@ -54,6 +54,7 @@ private slots: void enableDisable_QTBUG_36350(); void disabledAtStart(); void clearImplicitTarget(); + void onWithoutASignal(); private: QQmlEngine engine; @@ -397,6 +398,15 @@ void tst_qqmlconnections::clearImplicitTarget() delete item; } +void tst_qqmlconnections::onWithoutASignal() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("connection-no-signal-name.qml")); + QVERIFY(c.isError()); // Cannot assign to non-existent property "on" expected + QScopedPointer<QQuickItem> item(qobject_cast<QQuickItem*>(c.create())); + QVERIFY(item == nullptr); // should parse error, and not give us an item (or crash). +} + QTEST_MAIN(tst_qqmlconnections) #include "tst_qqmlconnections.moc" diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp index 574e6e2834..783b5cb786 100644 --- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp +++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp @@ -49,6 +49,7 @@ private slots: void engineMethod(); void parentContext(); void setContextProperty(); + void setContextProperties(); void setContextObject(); void destruction(); void idAsContextProperty(); @@ -366,6 +367,32 @@ void tst_qqmlcontext::setContextProperty() } } +void tst_qqmlcontext::setContextProperties() +{ + QQmlContext ctxt(&engine); + + TestObject obj1; + obj1.setA(3345); + TestObject obj2; + obj2.setA(-19); + + QVector<QQmlContext::PropertyPair> properties; + + properties.append({QString("a"), QVariant(10)}); + properties.append({QString("b"), QVariant(19)}); + properties.append({QString("d"), QVariant::fromValue<TestObject*>(&obj2)}); + properties.append({QString("c"), QVariant(QString("Hello World!"))}); + properties.append({QString("e"), QVariant::fromValue<TestObject*>(&obj1)}); + + ctxt.setContextProperties(properties); + + TEST_CONTEXT_PROPERTY(&ctxt, a, QVariant(10)); + TEST_CONTEXT_PROPERTY(&ctxt, b, QVariant(19)); + TEST_CONTEXT_PROPERTY(&ctxt, c, QVariant(QString("Hello World!"))); + TEST_CONTEXT_PROPERTY(&ctxt, d.a, QVariant(-19)); + TEST_CONTEXT_PROPERTY(&ctxt, e.a, QVariant(3345)); +} + void tst_qqmlcontext::setContextObject() { QQmlContext ctxt(&engine); @@ -777,7 +804,7 @@ void tst_qqmlcontext::contextLeak() QV4::Scope scope(ddata->jsWrapper.engine()); QV4::ScopedValue scriptContextWrapper(scope); scriptContextWrapper = context->importedScripts.valueRef()->as<QV4::Object>()->getIndexed(0); - scriptContext = scriptContextWrapper->as<QV4::QmlContextWrapper>()->getContext(); + scriptContext = scriptContextWrapper->as<QV4::QQmlContextWrapper>()->getContext(); } } diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.1.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.1.qml index efca6cdb80..8912d2a314 100644 --- a/tests/auto/qml/qqmlecmascript/data/assignDate.1.qml +++ b/tests/auto/qml/qqmlecmascript/data/assignDate.1.qml @@ -11,25 +11,26 @@ MyTypeObject { dateTimeProperty = dateTimeVar dateTimeProperty2 = dateTimeVar2 - // Commented properties do not currently test true: - boolProperty = //(dateProperty.getTime() == dateVar.getTime()) && + boolProperty = (dateProperty.getTime() == dateVar.getTime()) && (dateProperty.getFullYear() == 2009) && (dateProperty.getMonth() == 5-1) && - //(dateProperty.getDate() == 12) && - (dateProperty.getHours() == 0) && + (dateProperty.getUTCDate() == 12) && + (dateProperty.getUTCHours() == 0) && + (dateProperty.getUTCMinutes() == 0) && + (dateProperty.getUTCSeconds() == 0) && (dateTimeProperty.getTime() == dateTimeVar.getTime()) && (dateTimeProperty.getFullYear() == 2009) && (dateTimeProperty.getMonth() == 5-1) && - //(dateTimeProperty.getDate() == 12) && - //(dateTimeProperty.getHours() == 0) && - (dateTimeProperty.getMinutes() == 0) && - (dateTimeProperty.getSeconds() == 1) && + (dateTimeProperty.getUTCDate() == 12) && + (dateTimeProperty.getUTCHours() == 0) && + (dateTimeProperty.getUTCMinutes() == 0) && + (dateTimeProperty.getUTCSeconds() == 1) && (dateTimeProperty2.getTime() == dateTimeVar2.getTime()) && (dateTimeProperty2.getFullYear() == 2009) && (dateTimeProperty2.getMonth() == 5-1) && - //(dateTimeProperty2.getDate() == 12) && - //(dateTimeProperty2.getHours() == 23) && - (dateTimeProperty2.getMinutes() == 59) && - (dateTimeProperty2.getSeconds() == 59) + (dateTimeProperty2.getUTCDate() == 12) && + (dateTimeProperty2.getUTCHours() == 23) && + (dateTimeProperty2.getUTCMinutes() == 59) && + (dateTimeProperty2.getUTCSeconds() == 59) } } diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.2.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.2.qml index 71dd188f05..f8c1f6eb8f 100644 --- a/tests/auto/qml/qqmlecmascript/data/assignDate.2.qml +++ b/tests/auto/qml/qqmlecmascript/data/assignDate.2.qml @@ -12,24 +12,25 @@ MyTypeObject { var dateTimeVar = new Date("2009-05-12T00:00:01") var dateTimeVar2 = new Date("2009-05-12T23:59:59") - // Commented properties do not currently test true: - boolProperty = //(dateProperty.getTime() == dateVar.getTime()) && + boolProperty = (dateProperty.getTime() == dateVar.getTime()) && (dateProperty.getFullYear() == 2009) && (dateProperty.getMonth() == 5-1) && - //(dateProperty.getDate() == 12) && - (dateProperty.getHours() == 0) && + (dateProperty.getUTCDate() == 12) && + (dateProperty.getUTCHours() == 0) && + (dateProperty.getUTCMinutes() == 0) && + (dateProperty.getUTCSeconds() == 0) && (dateTimeProperty.getTime() == dateTimeVar.getTime()) && (dateTimeProperty.getFullYear() == 2009) && (dateTimeProperty.getMonth() == 5-1) && - //(dateTimeProperty.getDate() == 12) && - //(dateTimeProperty.getHours() == 0) && + (dateTimeProperty.getDate() == 12) && + (dateTimeProperty.getHours() == 0) && (dateTimeProperty.getMinutes() == 0) && (dateTimeProperty.getSeconds() == 1) && (dateTimeProperty2.getTime() == dateTimeVar2.getTime()) && (dateTimeProperty2.getFullYear() == 2009) && (dateTimeProperty2.getMonth() == 5-1) && - //(dateTimeProperty2.getDate() == 12) && - //(dateTimeProperty2.getHours() == 23) && + (dateTimeProperty2.getDate() == 12) && + (dateTimeProperty2.getHours() == 23) && (dateTimeProperty2.getMinutes() == 59) && (dateTimeProperty2.getSeconds() == 59) } diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.3.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.3.qml index 2cf740645c..e960eef193 100644 --- a/tests/auto/qml/qqmlecmascript/data/assignDate.3.qml +++ b/tests/auto/qml/qqmlecmascript/data/assignDate.3.qml @@ -2,35 +2,36 @@ import Qt.test 1.0 import QtQuick 2.0 MyTypeObject { - dateProperty: if (1) "2009-05-12Z" + dateProperty: if (1) "2009-05-12" dateTimeProperty: if (1) "2009-05-12T00:00:01Z" dateTimeProperty2: if (1) "2009-05-12T23:59:59Z" boolProperty: false Component.onCompleted: { - var dateVar = new Date("2009-05-12Z") + var dateVar = new Date("2009-05-12") var dateTimeVar = new Date("2009-05-12T00:00:01Z") var dateTimeVar2 = new Date("2009-05-12T23:59:59Z") - // Commented properties do not currently test true: - boolProperty = //(dateProperty.getTime() == dateVar.getTime()) && + boolProperty = (dateProperty.getTime() == dateVar.getTime()) && (dateProperty.getFullYear() == 2009) && (dateProperty.getMonth() == 5-1) && - //(dateProperty.getDate() == 12) && - (dateProperty.getHours() == 0) && + (dateProperty.getUTCDate() == 12) && + (dateProperty.getUTCHours() == 0) && + (dateProperty.getUTCMinutes() == 0) && + (dateProperty.getUTCSeconds() == 0) && (dateTimeProperty.getTime() == dateTimeVar.getTime()) && (dateTimeProperty.getFullYear() == 2009) && (dateTimeProperty.getMonth() == 5-1) && - //(dateTimeProperty.getDate() == 12) && - //(dateTimeProperty.getHours() == 0) && - (dateTimeProperty.getMinutes() == 0) && - (dateTimeProperty.getSeconds() == 1) && + (dateTimeProperty.getUTCDate() == 12) && + (dateTimeProperty.getUTCHours() == 0) && + (dateTimeProperty.getUTCMinutes() == 0) && + (dateTimeProperty.getUTCSeconds() == 1) && (dateTimeProperty2.getTime() == dateTimeVar2.getTime()) && (dateTimeProperty2.getFullYear() == 2009) && (dateTimeProperty2.getMonth() == 5-1) && - //(dateTimeProperty2.getDate() == 12) && - //(dateTimeProperty2.getHours() == 23) && - (dateTimeProperty2.getMinutes() == 59) && - (dateTimeProperty2.getSeconds() == 59) + (dateTimeProperty2.getUTCDate() == 12) && + (dateTimeProperty2.getUTCHours() == 23) && + (dateTimeProperty2.getUTCMinutes() == 59) && + (dateTimeProperty2.getUTCSeconds() == 59) } } diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.4.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.4.qml index 9b4975c833..6dd29afbc9 100644 --- a/tests/auto/qml/qqmlecmascript/data/assignDate.4.qml +++ b/tests/auto/qml/qqmlecmascript/data/assignDate.4.qml @@ -2,35 +2,36 @@ import Qt.test 1.0 import QtQuick 2.0 MyTypeObject { - dateProperty: if (1) new Date("2009-05-12Z") + dateProperty: if (1) new Date("2009-05-12") dateTimeProperty: if (1) new Date("2009-05-12T00:00:01Z") dateTimeProperty2: if (1) new Date("2009-05-12T23:59:59Z") boolProperty: false Component.onCompleted: { - var dateVar = new Date("2009-05-12Z") + var dateVar = new Date("2009-05-12") var dateTimeVar = new Date("2009-05-12T00:00:01Z") var dateTimeVar2 = new Date("2009-05-12T23:59:59Z") - // Commented properties do not currently test true: - boolProperty = //(dateProperty.getTime() == dateVar.getTime()) && + boolProperty = (dateProperty.getTime() == dateVar.getTime()) && (dateProperty.getFullYear() == 2009) && (dateProperty.getMonth() == 5-1) && - //(dateProperty.getDate() == 12) && - (dateProperty.getHours() == 0) && + (dateProperty.getUTCDate() == 12) && + (dateProperty.getUTCHours() == 0) && + (dateProperty.getUTCMinutes() == 0) && + (dateProperty.getUTCSeconds() == 0) && (dateTimeProperty.getTime() == dateTimeVar.getTime()) && (dateTimeProperty.getFullYear() == 2009) && (dateTimeProperty.getMonth() == 5-1) && - //(dateTimeProperty.getDate() == 12) && - //(dateTimeProperty.getHours() == 0) && - (dateTimeProperty.getMinutes() == 0) && - (dateTimeProperty.getSeconds() == 1) && + (dateTimeProperty.getUTCDate() == 12) && + (dateTimeProperty.getUTCHours() == 0) && + (dateTimeProperty.getUTCMinutes() == 0) && + (dateTimeProperty.getUTCSeconds() == 1) && (dateTimeProperty2.getTime() == dateTimeVar2.getTime()) && (dateTimeProperty2.getFullYear() == 2009) && (dateTimeProperty2.getMonth() == 5-1) && - //(dateTimeProperty2.getDate() == 12) && - //(dateTimeProperty2.getHours() == 23) && - (dateTimeProperty2.getMinutes() == 59) && - (dateTimeProperty2.getSeconds() == 59) + (dateTimeProperty2.getUTCDate() == 12) && + (dateTimeProperty2.getUTCHours() == 23) && + (dateTimeProperty2.getUTCMinutes() == 59) && + (dateTimeProperty2.getUTCSeconds() == 59) } } diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.5.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.5.qml index 2cf740645c..cfadaafc54 100644 --- a/tests/auto/qml/qqmlecmascript/data/assignDate.5.qml +++ b/tests/auto/qml/qqmlecmascript/data/assignDate.5.qml @@ -2,35 +2,36 @@ import Qt.test 1.0 import QtQuick 2.0 MyTypeObject { - dateProperty: if (1) "2009-05-12Z" - dateTimeProperty: if (1) "2009-05-12T00:00:01Z" - dateTimeProperty2: if (1) "2009-05-12T23:59:59Z" + dateProperty: if (1) "2009-05-12" + dateTimeProperty: if (1) "2009-05-12T00:00:01+02:00" + dateTimeProperty2: if (1) "2009-05-12T23:59:59+02:00" boolProperty: false Component.onCompleted: { - var dateVar = new Date("2009-05-12Z") - var dateTimeVar = new Date("2009-05-12T00:00:01Z") - var dateTimeVar2 = new Date("2009-05-12T23:59:59Z") + var dateVar = new Date("2009-05-12") + var dateTimeVar = new Date("2009-05-12T00:00:01+02:00") + var dateTimeVar2 = new Date("2009-05-12T23:59:59+02:00") - // Commented properties do not currently test true: - boolProperty = //(dateProperty.getTime() == dateVar.getTime()) && + boolProperty = (dateProperty.getTime() == dateVar.getTime()) && (dateProperty.getFullYear() == 2009) && (dateProperty.getMonth() == 5-1) && - //(dateProperty.getDate() == 12) && - (dateProperty.getHours() == 0) && + (dateProperty.getUTCDate() == 12) && + (dateProperty.getUTCHours() == 0) && + (dateProperty.getUTCMinutes() == 0) && + (dateProperty.getUTCSeconds() == 0) && (dateTimeProperty.getTime() == dateTimeVar.getTime()) && (dateTimeProperty.getFullYear() == 2009) && (dateTimeProperty.getMonth() == 5-1) && - //(dateTimeProperty.getDate() == 12) && - //(dateTimeProperty.getHours() == 0) && - (dateTimeProperty.getMinutes() == 0) && - (dateTimeProperty.getSeconds() == 1) && + (dateTimeProperty.getUTCDate() == 11) && + (dateTimeProperty.getUTCHours() == 22) && + (dateTimeProperty.getUTCMinutes() == 0) && + (dateTimeProperty.getUTCSeconds() == 1) && (dateTimeProperty2.getTime() == dateTimeVar2.getTime()) && (dateTimeProperty2.getFullYear() == 2009) && (dateTimeProperty2.getMonth() == 5-1) && - //(dateTimeProperty2.getDate() == 12) && - //(dateTimeProperty2.getHours() == 23) && - (dateTimeProperty2.getMinutes() == 59) && - (dateTimeProperty2.getSeconds() == 59) + (dateTimeProperty2.getUTCDate() == 12) && + (dateTimeProperty2.getUTCHours() == 21) && + (dateTimeProperty2.getUTCMinutes() == 59) && + (dateTimeProperty2.getUTCSeconds() == 59) } } diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.6.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.6.qml index 73e26db0c8..97cd0d1e60 100644 --- a/tests/auto/qml/qqmlecmascript/data/assignDate.6.qml +++ b/tests/auto/qml/qqmlecmascript/data/assignDate.6.qml @@ -3,34 +3,35 @@ import QtQuick 2.0 MyTypeObject { dateProperty: if (1) new Date("2009-05-12") - dateTimeProperty: if (1) new Date("2009-05-12T02:00:01+02:00") - dateTimeProperty2: if (1) new Date("2009-05-13T01:59:59+02:00") + dateTimeProperty: if (1) new Date("2009-05-12T00:00:01+02:00") + dateTimeProperty2: if (1) new Date("2009-05-12T23:59:59+02:00") boolProperty: false Component.onCompleted: { var dateVar = new Date("2009-05-12") - var dateTimeVar = new Date("2009-05-12T02:00:01+02:00") - var dateTimeVar2 = new Date("2009-05-13T01:59:59+02:00") + var dateTimeVar = new Date("2009-05-12T00:00:01+02:00") + var dateTimeVar2 = new Date("2009-05-12T23:59:59+02:00") - // Commented properties do not currently test true: - boolProperty = //(dateProperty.getTime() == dateVar.getTime()) && + boolProperty = (dateProperty.getTime() == dateVar.getTime()) && (dateProperty.getFullYear() == 2009) && (dateProperty.getMonth() == 5-1) && - //(dateProperty.getDate() == 12) && - (dateProperty.getHours() == 0) && + (dateProperty.getUTCDate() == 12) && + (dateProperty.getUTCHours() == 0) && + (dateProperty.getUTCMinutes() == 0) && + (dateProperty.getUTCSeconds() == 0) && (dateTimeProperty.getTime() == dateTimeVar.getTime()) && (dateTimeProperty.getFullYear() == 2009) && (dateTimeProperty.getMonth() == 5-1) && - //(dateTimeProperty.getDate() == 12) && - //(dateTimeProperty.getHours() == 0) && - (dateTimeProperty.getMinutes() == 0) && - (dateTimeProperty.getSeconds() == 1) && + (dateTimeProperty.getUTCDate() == 11) && + (dateTimeProperty.getUTCHours() == 22) && + (dateTimeProperty.getUTCMinutes() == 0) && + (dateTimeProperty.getUTCSeconds() == 1) && (dateTimeProperty2.getTime() == dateTimeVar2.getTime()) && (dateTimeProperty2.getFullYear() == 2009) && (dateTimeProperty2.getMonth() == 5-1) && - //(dateTimeProperty2.getDate() == 12) && - //(dateTimeProperty2.getHours() == 23) && - (dateTimeProperty2.getMinutes() == 59) && - (dateTimeProperty2.getSeconds() == 59) + (dateTimeProperty2.getUTCDate() == 12) && + (dateTimeProperty2.getUTCHours() == 21) && + (dateTimeProperty2.getUTCMinutes() == 59) && + (dateTimeProperty2.getUTCSeconds() == 59) } } diff --git a/tests/auto/qml/qqmlecmascript/data/assignDate.qml b/tests/auto/qml/qqmlecmascript/data/assignDate.qml index 14fe20787b..73677e99f1 100644 --- a/tests/auto/qml/qqmlecmascript/data/assignDate.qml +++ b/tests/auto/qml/qqmlecmascript/data/assignDate.qml @@ -7,28 +7,31 @@ MyTypeObject { var dateTimeVar = new Date("2009-05-12T00:00:01") var dateTimeVar2 = new Date("2009-05-12T23:59:59") + // Date, with no zone specified, is implicitly UTC dateProperty = dateVar + // Date-time, with no zone, is implicitly local-time dateTimeProperty = dateTimeVar dateTimeProperty2 = dateTimeVar2 - // Commented properties do not currently test true: - boolProperty = //(dateProperty.getTime() == dateVar.getTime()) && + boolProperty = (dateProperty.getTime() == dateVar.getTime()) && (dateProperty.getFullYear() == 2009) && (dateProperty.getMonth() == 5-1) && - //(dateProperty.getDate() == 12) && - (dateProperty.getHours() == 0) && + (dateProperty.getDate() == 12) && + (dateProperty.getUTCHours() == 0) && + (dateProperty.getUTCMinutes() == 0) && + (dateProperty.getUTCSeconds() == 0) && (dateTimeProperty.getTime() == dateTimeVar.getTime()) && (dateTimeProperty.getFullYear() == 2009) && (dateTimeProperty.getMonth() == 5-1) && - //(dateTimeProperty.getDate() == 12) && - //(dateTimeProperty.getHours() == 0) && + (dateTimeProperty.getDate() == 12) && + (dateTimeProperty.getHours() == 0) && (dateTimeProperty.getMinutes() == 0) && (dateTimeProperty.getSeconds() == 1) && (dateTimeProperty2.getTime() == dateTimeVar2.getTime()) && (dateTimeProperty2.getFullYear() == 2009) && (dateTimeProperty2.getMonth() == 5-1) && - //(dateTimeProperty2.getDate() == 12) && - //(dateTimeProperty2.getHours() == 23) && + (dateTimeProperty2.getDate() == 12) && + (dateTimeProperty2.getHours() == 23) && (dateTimeProperty2.getMinutes() == 59) && (dateTimeProperty2.getSeconds() == 59) } diff --git a/tests/auto/qml/qqmlecmascript/data/dynamicString.qml b/tests/auto/qml/qqmlecmascript/data/dynamicString.qml index 5693794c71..c704161eb5 100644 --- a/tests/auto/qml/qqmlecmascript/data/dynamicString.qml +++ b/tests/auto/qml/qqmlecmascript/data/dynamicString.qml @@ -11,6 +11,6 @@ MyTypeObject { date.setHours(5); date.setMinutes(30); date.setSeconds(50); - stringProperty = stringProperty.arg("Hello World").arg(false).arg(true).arg(100).arg(-100).arg(3.1415926).arg(Qt.formatDateTime(date, "yyyy-MM-dd hh::mm:ss")); + stringProperty = stringProperty.arg("Hello World").arg(false).arg(true).arg(100).arg(-100).arg(Math.PI).arg(Qt.formatDateTime(date, "yyyy-MM-dd hh::mm:ss")); } } diff --git a/tests/auto/qml/qqmlecmascript/data/nonNotifyableConstant.qml b/tests/auto/qml/qqmlecmascript/data/nonNotifyableConstant.qml new file mode 100644 index 0000000000..424b3e8b07 --- /dev/null +++ b/tests/auto/qml/qqmlecmascript/data/nonNotifyableConstant.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +MyQmlObject { + objectName: trueProperty ? "foo" : "bar" +} diff --git a/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml b/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml index 74c7cda9a3..c6732efc05 100644 --- a/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml +++ b/tests/auto/qml/qqmlecmascript/data/sequenceSort.qml @@ -52,7 +52,11 @@ Item { function doStringTest(stringList, fn) { var expected = createExpected(stringList, fn); var actual = msc.strings(stringList); - return checkResults(expected, actual, fn); + var actual2 = msc.stringsVector(stringList); + var actual3 = msc.stringsStdVector(stringList); + return checkResults(expected, actual, fn) + && checkResults(expected, actual2, fn) + && checkResults(expected, actual3, fn) } function doIntTest(intList, fn) { var expected = createExpected(intList, fn); @@ -67,12 +71,16 @@ Item { function doIntVectorTest(intList, fn) { var expected = createExpected(intList, fn); var actual = msc.integerVector(intList); - return checkResults(expected, actual, fn); + var actual2 = msc.integerStdVector(intList); + return checkResults(expected, actual, fn) + && checkResults(expected, actual2, fn) } function doRealVectorTest(realList, fn) { var expected = createExpected(realList, fn); var actual = msc.realVector(realList); - return checkResults(expected, actual, fn); + var actual2 = msc.realStdVector(realList); + return checkResults(expected, actual, fn) + && checkResults(expected, actual2, fn) } function test_qtbug_25269(useCustomCompare) { diff --git a/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro b/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro index 101181bba0..0dd9365366 100644 --- a/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro +++ b/tests/auto/qml/qqmlecmascript/qqmlecmascript.pro @@ -7,7 +7,6 @@ SOURCES += tst_qqmlecmascript.cpp \ ../../shared/testhttpserver.cpp HEADERS += testtypes.h \ ../../shared/testhttpserver.h -INCLUDEPATH += ../../shared RESOURCES += qqmlecmascript.qrc diff --git a/tests/auto/qml/qqmlecmascript/testtypes.cpp b/tests/auto/qml/qqmlecmascript/testtypes.cpp index 13bb0435cd..80da5d7e52 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.cpp +++ b/tests/auto/qml/qqmlecmascript/testtypes.cpp @@ -290,6 +290,15 @@ public: { return stringList; } + Q_INVOKABLE QVector<QString> stringsVector(const QStringList& stringList) const + { + return stringList.toVector(); + } + Q_INVOKABLE + std::vector<QString> stringsStdVector(const QStringList& stringList) const + { + return std::vector<QString>(stringList.begin(), stringList.end()); + } Q_INVOKABLE QList<int> integers(QList<int> v) const { return v; @@ -306,14 +315,29 @@ public: { return v; } + Q_INVOKABLE + std::vector<int> integerStdVector(std::vector<int> v) const + { + return v; + } Q_INVOKABLE QVector<qreal> realVector(QVector<qreal> v) const { return v; } + Q_INVOKABLE + std::vector<qreal> realStdVector(std::vector<qreal> v) const + { + return v; + } Q_INVOKABLE QVector<bool> boolVector(QVector<bool> v) const { return v; } + Q_INVOKABLE + std::vector<bool> boolStdVector(std::vector<bool> v) const + { + return v; + } }; static MyInheritedQmlObject *theSingletonObject = 0; diff --git a/tests/auto/qml/qqmlecmascript/testtypes.h b/tests/auto/qml/qqmlecmascript/testtypes.h index ec20714c51..8d89df31db 100644 --- a/tests/auto/qml/qqmlecmascript/testtypes.h +++ b/tests/auto/qml/qqmlecmascript/testtypes.h @@ -1262,7 +1262,6 @@ public: { CircularReferenceObject *retn = new CircularReferenceObject(parent); retn->m_dtorCount = m_dtorCount; - retn->m_engine = m_engine; return retn; } @@ -1283,14 +1282,8 @@ public: thisObject->defineDefaultProperty(QStringLiteral("autoTestStrongRef"), v); } - void setEngine(QQmlEngine* declarativeEngine) - { - m_engine = QQmlEnginePrivate::get(declarativeEngine)->v8engine(); - } - private: int *m_dtorCount; - QV8Engine* m_engine; }; Q_DECLARE_METATYPE(CircularReferenceObject*) diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index 14447383c1..5e752d124b 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2017 Crimson AS <info@crimson.no> ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** @@ -42,6 +43,7 @@ #include "../../shared/util.h" #include <private/qv4functionobject_p.h> #include <private/qv4scopedvalue_p.h> +#include <private/qv4jscall_p.h> #include <private/qv4alloca_p.h> #include <private/qv4runtime_p.h> #include <private/qv4object_p.h> @@ -259,6 +261,7 @@ private slots: void doubleEvaluate(); void forInLoop(); void nonNotifyable(); + void nonNotifyableConstant(); void deleteWhileBindingRunning(); void callQtInvokables(); void resolveClashingProperties(); @@ -335,9 +338,17 @@ private slots: void stringify_qtbug_50592(); void instanceof_data(); void instanceof(); + void constkw_data(); + void constkw(); + void redefineGlobalProp(); void freeze_empty_object(); void singleBlockLoops(); void qtbug_60547(); + void delayLoadingArgs(); + void manyArguments(); + void forInIterator(); + void localForInIterator(); + void shadowedFunctionName(); void anotherNaN(); private: @@ -440,29 +451,37 @@ void tst_qqmlecmascript::assignBasicTypes() void tst_qqmlecmascript::assignDate_data() { QTest::addColumn<QUrl>("source"); + QTest::addColumn<int>("timeOffset"); // -1 for local-time, else minutes from UTC - QTest::newRow("Component.onComplete JS Parse") << testFileUrl("assignDate.qml"); - QTest::newRow("Component.onComplete JS") << testFileUrl("assignDate.1.qml"); - QTest::newRow("Binding JS") << testFileUrl("assignDate.2.qml"); - QTest::newRow("Binding UTC") << testFileUrl("assignDate.3.qml"); - QTest::newRow("Binding JS UTC") << testFileUrl("assignDate.4.qml"); - QTest::newRow("Binding UTC+2") << testFileUrl("assignDate.5.qml"); - QTest::newRow("Binding JS UTC+2 ") << testFileUrl("assignDate.6.qml"); + QTest::newRow("Component.onComplete JS Parse") << testFileUrl("assignDate.qml") << -1; + QTest::newRow("Component.onComplete JS") << testFileUrl("assignDate.1.qml") << 0; + QTest::newRow("Binding JS") << testFileUrl("assignDate.2.qml") << -1; + QTest::newRow("Binding UTC") << testFileUrl("assignDate.3.qml") << 0; + QTest::newRow("Binding JS UTC") << testFileUrl("assignDate.4.qml") << 0; + QTest::newRow("Binding UTC+2") << testFileUrl("assignDate.5.qml") << 120; + QTest::newRow("Binding JS UTC+2 ") << testFileUrl("assignDate.6.qml") << 120; } void tst_qqmlecmascript::assignDate() { QFETCH(QUrl, source); + QFETCH(int, timeOffset); QQmlComponent component(&engine, source); QScopedPointer<QObject> obj(component.create()); MyTypeObject *object = qobject_cast<MyTypeObject *>(obj.data()); QVERIFY(object != 0); - // Dates received from JS are automatically converted to local time - QDate expectedDate(QDateTime(QDate(2009, 5, 12), QTime(0, 0, 0), Qt::UTC).toLocalTime().date()); - QDateTime expectedDateTime(QDateTime(QDate(2009, 5, 12), QTime(0, 0, 1), Qt::UTC).toLocalTime()); - QDateTime expectedDateTime2(QDateTime(QDate(2009, 5, 12), QTime(23, 59, 59), Qt::UTC).toLocalTime()); + QDate expectedDate(2009, 5, 12); + QDateTime expectedDateTime; + QDateTime expectedDateTime2; + if (timeOffset == -1) { + expectedDateTime = QDateTime(QDate(2009, 5, 12), QTime(0, 0, 1), Qt::LocalTime); + expectedDateTime2 = QDateTime(QDate(2009, 5, 12), QTime(23, 59, 59), Qt::LocalTime); + } else { + expectedDateTime = QDateTime(QDate(2009, 5, 12), QTime(0, 0, 1), Qt::OffsetFromUTC, timeOffset * 60); + expectedDateTime2 = QDateTime(QDate(2009, 5, 12), QTime(23, 59, 59), Qt::OffsetFromUTC, timeOffset * 60); + } QCOMPARE(object->dateProperty(), expectedDate); QCOMPARE(object->dateTimeProperty(), expectedDateTime); @@ -2329,13 +2348,13 @@ void tst_qqmlecmascript::regExpBug() } } -static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const char *source) +static inline bool evaluate_error(QV4::ExecutionEngine *v4, const QV4::Value &o, const char *source) { QString functionSource = QLatin1String("(function(object) { return ") + QLatin1String(source) + QLatin1String(" })"); - QV4::Scope scope(QV8Engine::getV4(engine)); - QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), functionSource); + QV4::Scope scope(v4); + QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::EvalCode, functionSource); program.inheritContext = true; QV4::ScopedFunctionObject function(scope, program.run()); @@ -2343,10 +2362,10 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const scope.engine->catchException(); return true; } - QV4::ScopedCallData d(scope, 1); - d->args[0] = o; - d->thisObject = engine->global(); - function->call(scope, d); + QV4::JSCallData jsCallData(scope, 1); + jsCallData->args[0] = o; + *jsCallData->thisObject = v4->global(); + function->call(jsCallData); if (scope.engine->hasException) { scope.engine->catchException(); return true; @@ -2354,14 +2373,14 @@ static inline bool evaluate_error(QV8Engine *engine, const QV4::Value &o, const return false; } -static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, +static inline bool evaluate_value(QV4::ExecutionEngine *v4, const QV4::Value &o, const char *source, const QV4::Value &result) { QString functionSource = QLatin1String("(function(object) { return ") + QLatin1String(source) + QLatin1String(" })"); - QV4::Scope scope(QV8Engine::getV4(engine)); - QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), functionSource); + QV4::Scope scope(v4); + QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::EvalCode, functionSource); program.inheritContext = true; QV4::ScopedFunctionObject function(scope, program.run()); @@ -2372,26 +2391,27 @@ static inline bool evaluate_value(QV8Engine *engine, const QV4::Value &o, if (!function) return false; - QV4::ScopedCallData d(scope, 1); - d->args[0] = o; - d->thisObject = engine->global(); - function->call(scope, d); + QV4::ScopedValue value(scope); + QV4::JSCallData jsCallData(scope, 1); + jsCallData->args[0] = o; + *jsCallData->thisObject = v4->global(); + value = function->call(jsCallData); if (scope.engine->hasException) { scope.engine->catchException(); return false; } - return QV4::Runtime::method_strictEqual(scope.result, result); + return QV4::Runtime::method_strictEqual(value, result); } -static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o, - const char *source) +static inline QV4::ReturnedValue evaluate(QV4::ExecutionEngine *v4, const QV4::Value &o, + const char *source) { QString functionSource = QLatin1String("(function(object) { return ") + QLatin1String(source) + QLatin1String(" })"); - QV4::Scope scope(QV8Engine::getV4(engine)); + QV4::Scope scope(v4); - QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), functionSource); + QV4::Script program(QV4::ScopedContext(scope, scope.engine->rootContext()), QV4::Compiler::EvalCode, functionSource); program.inheritContext = true; QV4::ScopedFunctionObject function(scope, program.run()); @@ -2401,15 +2421,15 @@ static inline QV4::ReturnedValue evaluate(QV8Engine *engine, const QV4::Value &o } if (!function) return QV4::Encode::undefined(); - QV4::ScopedCallData d(scope, 1); - d->args[0] = o; - d->thisObject = engine->global(); - function->call(scope, d); + QV4::JSCallData jsCallData(scope, 1); + jsCallData->args[0] = o; + *jsCallData->thisObject = v4->global(); + QV4::ScopedValue result(scope, function->call(jsCallData)); if (scope.engine->hasException) { scope.engine->catchException(); return QV4::Encode::undefined(); } - return scope.result.asReturnedValue(); + return result->asReturnedValue(); } #define EVALUATE_ERROR(source) evaluate_error(engine, object, source) @@ -2423,12 +2443,11 @@ void tst_qqmlecmascript::callQtInvokables() MyInvokableObject *o = new MyInvokableObject(); QQmlEngine qmlengine; - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(&qmlengine); - QV8Engine *engine = ep->v8engine(); - QV4::Scope scope(QV8Engine::getV4(engine)); + QV4::ExecutionEngine *engine = qmlengine.handle(); + QV4::Scope scope(engine); - QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(QV8Engine::getV4(engine), o)); + QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(engine, o)); // Non-existent methods o->reset(); @@ -2996,9 +3015,8 @@ void tst_qqmlecmascript::resolveClashingProperties() { ClashingNames *o = new ClashingNames(); QQmlEngine qmlengine; - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(&qmlengine); - QV4::ExecutionEngine *engine = QV8Engine::getV4(ep->v8engine()); + QV4::ExecutionEngine *engine = qmlengine.handle(); QV4::Scope scope(engine); QV4::ScopedValue object(scope, QV4::QObjectWrapper::wrap(engine, o)); @@ -4028,11 +4046,10 @@ void tst_qqmlecmascript::verifyContextLifetime(QQmlContextData *ctxt) { QQmlContextData *childCtxt = ctxt->childContexts; if (!ctxt->importedScripts.isNullOrUndefined()) { - QV8Engine *engine = QV8Engine::get(ctxt->engine); - QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine); + QV4::ExecutionEngine *v4 = ctxt->engine->handle(); QV4::Scope scope(v4); QV4::ScopedArrayObject scripts(scope, ctxt->importedScripts.value()); - QV4::Scoped<QV4::QmlContextWrapper> qml(scope); + QV4::Scoped<QV4::QQmlContextWrapper> qml(scope); for (quint32 i = 0; i < scripts->getLength(); ++i) { QQmlContextData *scriptContext, *newContext; qml = scripts->getIndexed(i); @@ -4041,7 +4058,7 @@ void tst_qqmlecmascript::verifyContextLifetime(QQmlContextData *ctxt) { qml = QV4::Encode::undefined(); { - QV4::Scope scope(QV8Engine::getV4((engine))); + QV4::Scope scope(v4); QV4::ScopedContext temporaryScope(scope, QV4::QmlContext::create(scope.engine->rootContext(), scriptContext, 0)); Q_UNUSED(temporaryScope) } @@ -4358,8 +4375,7 @@ void tst_qqmlecmascript::scarceResources_other() QPixmap origPixmap(100, 100); origPixmap.fill(Qt::blue); QString srp_name, expectedWarning; - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(&engine); - QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); + QV4::ExecutionEngine *v4 = engine.handle(); ScarceResourceObject *eo = 0; QObject *srsc = 0; QObject *object = 0; @@ -4730,8 +4746,7 @@ void tst_qqmlecmascript::scarceResources() QFETCH(QVariantList, expectedValues); QFETCH(QStringList, expectedErrors); - QQmlEnginePrivate *ep = QQmlEnginePrivate::get(&engine); - QV4::ExecutionEngine *v4 = QV8Engine::getV4(ep->v8engine()); + QV4::ExecutionEngine *v4 = engine.handle(); ScarceResourceObject *eo = 0; QObject *object = 0; @@ -5171,9 +5186,9 @@ void tst_qqmlecmascript::propertyVarInheritance() // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only // public function which can return us a handle to something in the varProperties array. QV4::ReturnedValue tmp = icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")); - icoCanaryHandle.set(QQmlEnginePrivate::getV4Engine(&engine), tmp); + icoCanaryHandle.set(engine.handle(), tmp); tmp = ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")); - ccoCanaryHandle.set(QQmlEnginePrivate::getV4Engine(&engine), tmp); + ccoCanaryHandle.set(engine.handle(), tmp); tmp = QV4::Encode::null(); QVERIFY(!icoCanaryHandle.isUndefined()); QVERIFY(!ccoCanaryHandle.isUndefined()); @@ -5211,7 +5226,7 @@ void tst_qqmlecmascript::propertyVarInheritance2() QCOMPARE(childObject->property("textCanary").toInt(), 10); QV4::WeakValue childObjectVarArrayValueHandle; { - childObjectVarArrayValueHandle.set(QQmlEnginePrivate::getV4Engine(&engine), + childObjectVarArrayValueHandle.set(engine.handle(), QQmlVMEMetaObject::get(childObject)->vmeProperty(childObject->metaObject()->indexOfProperty("vp"))); QVERIFY(!childObjectVarArrayValueHandle.isUndefined()); gc(engine); @@ -5299,7 +5314,6 @@ void tst_qqmlecmascript::handleReferenceManagement() QObject *object = component.create(); QVERIFY(object != 0); CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro"); - cro->setEngine(&hrmEngine); cro->setDtorCount(&dtorCount); QMetaObject::invokeMethod(object, "createReference"); gc(hrmEngine); @@ -5319,7 +5333,6 @@ void tst_qqmlecmascript::handleReferenceManagement() QObject *object = component.create(); QVERIFY(object != 0); CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro"); - cro->setEngine(&hrmEngine); cro->setDtorCount(&dtorCount); QMetaObject::invokeMethod(object, "circularReference"); gc(hrmEngine); @@ -6232,10 +6245,6 @@ void tst_qqmlecmascript::include() void tst_qqmlecmascript::includeRemoteSuccess() { -#if defined(Q_CC_MSVC) && _MSC_VER == 1700 - QSKIP("This test does not work reliably with MSVC2012 on Win8 64-bit in release mode."); -#endif - // Remote - success TestHTTPServer server; QVERIFY2(server.listen(), qPrintable(server.errorString())); @@ -6881,6 +6890,18 @@ void tst_qqmlecmascript::nonNotifyable() delete object; } +void tst_qqmlecmascript::nonNotifyableConstant() +{ + QQmlComponent component(&engine, testFileUrl("nonNotifyableConstant.qml")); + QQmlTestMessageHandler messageHandler; + + // Shouldn't produce an error message about non-NOTIFYable properties, + // as the property has the CONSTANT attribute. + QScopedPointer<QObject> object(component.create()); + QVERIFY(object); + QCOMPARE(messageHandler.messages().size(), 0); +} + void tst_qqmlecmascript::forInLoop() { QQmlComponent component(&engine, testFileUrl("forInLoop.qml")); @@ -7278,8 +7299,8 @@ class WeakReferenceMutator : public QObject Q_OBJECT public: WeakReferenceMutator() - : resultPtr(Q_NULLPTR) - , weakRef(Q_NULLPTR) + : resultPtr(nullptr) + , weakRef(nullptr) {} void init(QV4::ExecutionEngine *v4, QV4::WeakValue *weakRef, bool *resultPtr) @@ -7298,7 +7319,7 @@ private slots: *resultPtr = weakRef->valueRef() && weakRef->isNullOrUndefined(); if (!*resultPtr) return; - QV4::ExecutionEngine *v4 = QV8Engine::getV4(qmlEngine(this)); + QV4::ExecutionEngine *v4 = qmlEngine(this)->handle(); weakRef->set(v4, v4->newObject()); *resultPtr = weakRef->valueRef() && !weakRef->isNullOrUndefined(); } @@ -7348,7 +7369,7 @@ void tst_qqmlecmascript::onDestructionViaGC() qmlRegisterType<WeakReferenceMutator>("Test", 1, 0, "WeakReferenceMutator"); QQmlEngine engine; - QV4::ExecutionEngine *v4 = QV8Engine::getV4(&engine); + QV4::ExecutionEngine *v4 =engine.handle(); QQmlComponent component(&engine, testFileUrl("DestructionHelper.qml")); @@ -8174,6 +8195,8 @@ void tst_qqmlecmascript::stringify_qtbug_50592() QCOMPARE(obj->property("source").toString(), QString::fromLatin1("http://example.org/some_nonexistant_image.png")); } +// Tests for the JS-only instanceof. Tests for the QML extensions for +// instanceof belong in tst_qqmllanguage! void tst_qqmlecmascript::instanceof_data() { QTest::addColumn<QString>("setupCode"); @@ -8226,7 +8249,7 @@ void tst_qqmlecmascript::instanceof() QJSEngine engine; QJSValue ret = engine.evaluate(setupCode + ";\n" + QTest::currentDataTag()); - if (expectedValue.type() == QMetaType::Bool) { + if (expectedValue.type() == QVariant::Bool) { bool returnValue = ret.toBool(); QVERIFY2(!ret.isError(), qPrintable(ret.toString())); QCOMPARE(returnValue, expectedValue.toBool()); @@ -8236,6 +8259,108 @@ void tst_qqmlecmascript::instanceof() } } +void tst_qqmlecmascript::constkw_data() +{ + QTest::addColumn<QString>("sourceCode"); + QTest::addColumn<bool>("exceptionExpected"); + QTest::addColumn<QVariant>("expectedValue"); + + QTest::newRow("simpleconst") + << "const v = 5\n" + "v\n" + << false + << QVariant(5); + QTest::newRow("twoconst") + << "const v = 5, i = 10\n" + "v + i\n" + << false + << QVariant(15); + QTest::newRow("constandvar") + << "const v = 5\n" + "var i = 20\n" + "v + i\n" + << false + << QVariant(25); + QTest::newRow("const-multiple-scopes-same-var") + << "const v = 3\n" + "function f() { const v = 1; return v; }\n" + "v + f()\n" + << false + << QVariant(4); + + // error cases + QTest::newRow("const-no-initializer") + << "const v\n" + << true + << QVariant("SyntaxError: Missing initializer in const declaration"); + QTest::newRow("const-no-initializer-comma") + << "const v = 1, i\n" + << true + << QVariant("SyntaxError: Missing initializer in const declaration"); + QTest::newRow("const-no-duplicate") + << "const v = 1, v = 2\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); + QTest::newRow("const-no-duplicate-2") + << "const v = 1\n" + "const v = 2\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); + QTest::newRow("const-no-duplicate-var") + << "const v = 1\n" + "var v = 1\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); + QTest::newRow("var-no-duplicate-const") + << "var v = 1\n" + "const v = 1\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); + QTest::newRow("const-no-duplicate-let") + << "const v = 1\n" + "let v = 1\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); + QTest::newRow("let-no-duplicate-const") + << "let v = 1\n" + "const v = 1\n" + << true + << QVariant("SyntaxError: Identifier v has already been declared"); +} + +void tst_qqmlecmascript::constkw() +{ + QFETCH(QString, sourceCode); + QFETCH(bool, exceptionExpected); + QFETCH(QVariant, expectedValue); + + QJSEngine engine; + QJSValue ret = engine.evaluate(sourceCode); + + if (!exceptionExpected) { + QVERIFY2(!ret.isError(), qPrintable(ret.toString())); + QCOMPARE(ret.toVariant(), expectedValue); + } else { + QVERIFY2(ret.isError(), qPrintable(ret.toString())); + QCOMPARE(ret.toString(), expectedValue.toString()); + } +} + +// Redefine a property found on the global object. It shouldn't throw. +void tst_qqmlecmascript::redefineGlobalProp() +{ + { + QJSEngine engine; + QJSValue ret = engine.evaluate("\"use strict\"\n var toString = 1;"); + QVERIFY2(!ret.isError(), qPrintable(ret.toString())); + } + { + QJSEngine engine; + QJSValue ret = engine.evaluate("var toString = 1;"); + QVERIFY2(!ret.isError(), qPrintable(ret.toString())); + } +} + void tst_qqmlecmascript::freeze_empty_object() { // this shouldn't crash @@ -8281,6 +8406,69 @@ void tst_qqmlecmascript::anotherNaN() object->setProperty("prop", d); // don't crash } +void tst_qqmlecmascript::delayLoadingArgs() +{ + QJSEngine engine; + QJSValue ret = engine.evaluate("(function(x){return x + (x+=2)})(20)"); + QCOMPARE(ret.toInt(), 42); // esp. not 44. +} + +void tst_qqmlecmascript::manyArguments() +{ + const char *testCase = + "function x() { var sum; for (var i = 0; i < arguments.length; ++i) sum += arguments[i][0]; }" + "x([0],[1],[2],[3],[4],[5],[6],[7],[8],[9], [0],[1],[2],[3],[4],[5],[6],[7],[8],[9], [0],[1],[2],[3],[4],[5],[6],[7],[8],[9])"; + + QJSEngine engine; + engine.evaluate(testCase); +} + +void tst_qqmlecmascript::forInIterator() +{ + auto testCase = + "(function(){\n" + "var x = 'yoyo'\n" + "var i\n" + "for (i in x) {\n" + "}\n" + "return i\n" + "})()"; + QJSEngine engine; + QJSValue ret = engine.evaluate(testCase); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QStringLiteral("3")); +} + +void tst_qqmlecmascript::localForInIterator() +{ + auto testCase = + "(function(){\n" + "var x = 'yoyo'\n" + "for (var i in x) {\n" + "}\n" + "return i\n" + "})()"; + QJSEngine engine; + QJSValue ret = engine.evaluate(testCase); + QVERIFY(ret.isString()); + QCOMPARE(ret.toString(), QStringLiteral("3")); +} + +void tst_qqmlecmascript::shadowedFunctionName() +{ + // verify that arguments shadow the function name + QJSEngine engine; + QJSValue v = engine.evaluate(QString::fromLatin1( + "function f(f) { return f; }\n" + "f(true)\n" + )); + QVERIFY(!v.isError()); + QVERIFY(v.isBool()); + QCOMPARE(v.toBool(), true); +} + + + QTEST_MAIN(tst_qqmlecmascript) #include "tst_qqmlecmascript.moc" diff --git a/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent1.qml b/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent1.qml new file mode 100644 index 0000000000..1047926750 --- /dev/null +++ b/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent1.qml @@ -0,0 +1,10 @@ +import QtQuick 2.8 + +Item { + property alias textEdit: textEdit + + TextEdit { + id: textEdit + + } +} diff --git a/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent2.qml b/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent2.qml new file mode 100644 index 0000000000..552c6c3791 --- /dev/null +++ b/tests/auto/qml/qqmlengine/data/GroupedPropertiesRevisionComponent2.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 + +Item { + property alias textEdit: textEdit + + TextEdit { + id: textEdit + + } +} diff --git a/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.1.qml b/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.1.qml new file mode 100644 index 0000000000..39bd01fe40 --- /dev/null +++ b/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.1.qml @@ -0,0 +1,7 @@ +import QtQuick 2.8 + +Item { + GroupedPropertiesRevisionComponent1 { + textEdit.onEditingFinished: console.log("test") + } +} diff --git a/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.2.qml b/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.2.qml new file mode 100644 index 0000000000..bb9ba79b01 --- /dev/null +++ b/tests/auto/qml/qqmlengine/data/testGroupedPropertiesRevision.2.qml @@ -0,0 +1,7 @@ +import QtQuick 2.8 + +Item { + GroupedPropertiesRevisionComponent2 { + textEdit.onEditingFinished: console.log("test") + } +} diff --git a/tests/auto/qml/qqmlengine/qqmlengine.pro b/tests/auto/qml/qqmlengine/qqmlengine.pro index e7952d8e3a..8d1e149d62 100644 --- a/tests/auto/qml/qqmlengine/qqmlengine.pro +++ b/tests/auto/qml/qqmlengine/qqmlengine.pro @@ -7,3 +7,8 @@ include (../../shared/util.pri) SOURCES += tst_qqmlengine.cpp QT += core-private gui-private qml-private network testlib + +boot2qt: { + # GC corruption test is too heavy for qemu-arm + DEFINES += SKIP_GCCORRUPTION_TEST +} diff --git a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp index dac6ddaebd..d6d7506c48 100644 --- a/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp +++ b/tests/auto/qml/qqmlengine/tst_qqmlengine.cpp @@ -75,6 +75,7 @@ private slots: void urlInterceptor(); void qmlContextProperties(); void testGCCorruption(); + void testGroupedPropertyRevisions(); public slots: QObject *createAQObjectForOwnershipTest () @@ -741,6 +742,9 @@ public: if (url.path().endsWith("Test.2/qmldir"))//Special case return QUrl::fromLocalFile(m_base.path() + "interception/module/intercepted/qmldir"); + // Special case: with 5.10 we always add the implicit import, so we need to explicitly handle this case now + if (url.path().endsWith("intercepted/qmldir")) + return url; QString alteredPath = url.path(); int a = alteredPath.lastIndexOf('/'); @@ -859,6 +863,10 @@ void tst_qqmlengine::qmlContextProperties() void tst_qqmlengine::testGCCorruption() { +#ifdef SKIP_GCCORRUPTION_TEST + QSKIP("Test too heavy for qemu"); +#endif + QQmlEngine e; QQmlComponent c(&e, testFileUrl("testGCCorruption.qml")); @@ -866,6 +874,17 @@ void tst_qqmlengine::testGCCorruption() QVERIFY2(o, qPrintable(c.errorString())); } +void tst_qqmlengine::testGroupedPropertyRevisions() +{ + QQmlEngine e; + + QQmlComponent c(&e, testFileUrl("testGroupedPropertiesRevision.1.qml")); + QScopedPointer<QObject> object(c.create()); + QVERIFY2(object.data(), qPrintable(c.errorString())); + QQmlComponent c2(&e, testFileUrl("testGroupedPropertiesRevision.2.qml")); + QVERIFY(!c2.errorString().isEmpty()); +} + QTEST_MAIN(tst_qqmlengine) #include "tst_qqmlengine.moc" diff --git a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp index 268010ead8..2511eebefe 100644 --- a/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp +++ b/tests/auto/qml/qqmlextensionplugin/tst_qqmlextensionplugin.cpp @@ -105,7 +105,7 @@ void tst_qqmlextensionplugin::iidCheck() QPluginLoader loader(filePath); QVERIFY2(loader.load(), qPrintable(loader.errorString())); - QVERIFY(loader.instance() != Q_NULLPTR); + QVERIFY(loader.instance() != nullptr); if (qobject_cast<QQmlExtensionPlugin *>(loader.instance())) { QString iid = loader.metaData().value(QStringLiteral("IID")).toString(); diff --git a/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro b/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro index 719fd6c350..542ec44736 100644 --- a/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro +++ b/tests/auto/qml/qqmlinstantiator/qqmlinstantiator.pro @@ -2,7 +2,6 @@ CONFIG += testcase TARGET = tst_qqmlinstantiator macx:CONFIG -= app_bundle -INCLUDEPATH += ../../shared/ SOURCES += tst_qqmlinstantiator.cpp HEADERS += stringmodel.h diff --git a/tests/auto/qml/qqmlinstantiator/stringmodel.h b/tests/auto/qml/qqmlinstantiator/stringmodel.h index 0bd4ada55e..b01817375a 100644 --- a/tests/auto/qml/qqmlinstantiator/stringmodel.h +++ b/tests/auto/qml/qqmlinstantiator/stringmodel.h @@ -65,7 +65,7 @@ public: return items.count(); } - virtual QHash<int, QByteArray> roleNames() const Q_DECL_OVERRIDE + QHash<int, QByteArray> roleNames() const override { return roles; } @@ -75,7 +75,7 @@ public: return 1; } - virtual bool hasChildren(const QModelIndex &) const Q_DECL_OVERRIDE + bool hasChildren(const QModelIndex &) const override { return rowCount(QModelIndex()) > 0; } diff --git a/tests/auto/qml/qqmlitemmodels/qtestmodel.h b/tests/auto/qml/qqmlitemmodels/qtestmodel.h index 8724ef927f..6a022b3135 100644 --- a/tests/auto/qml/qqmlitemmodels/qtestmodel.h +++ b/tests/auto/qml/qqmlitemmodels/qtestmodel.h @@ -91,8 +91,6 @@ public: } int rowCount(const QModelIndex& parent = QModelIndex()) const { - if (!fetched) - qFatal("%s: rowCount should not be called before fetching", Q_FUNC_INFO); if ((parent.column() > 0) || (level(parent) > levels) || (alternateChildlessRows && parent.row() > 0 && (parent.row() & 1))) return 0; diff --git a/tests/auto/qml/qqmllanguage/data/TypeWithEnum.qml b/tests/auto/qml/qqmllanguage/data/TypeWithEnum.qml new file mode 100644 index 0000000000..c6788f787a --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/TypeWithEnum.qml @@ -0,0 +1,28 @@ +import QtQuick 2.0 + +QtObject { + enum MyEnum { + EnumValue1, + EnumValue2, + EnumValue3 + } + + enum MyOtherEnum { + OtherEnumValue1 = 24, + OtherEnumValue2, + OtherEnumValue3 = 24, + OtherEnumValue4, + OtherEnumValue5 = 1 + } + + property int enumValue: TypeWithEnum.EnumValue2 + property int enumValue2 + property int scopedEnumValue: TypeWithEnum.MyEnum.EnumValue2 + Component.onCompleted: enumValue2 = TypeWithEnum.EnumValue3 + + property int otherEnumValue1: TypeWithEnum.OtherEnumValue1 + property int otherEnumValue2: TypeWithEnum.OtherEnumValue2 + property int otherEnumValue3: TypeWithEnum.OtherEnumValue3 + property int otherEnumValue4: TypeWithEnum.OtherEnumValue4 + property int otherEnumValue5: TypeWithEnum.OtherEnumValue5 +} diff --git a/tests/auto/qml/qqmllanguage/data/circularSingleton.qml b/tests/auto/qml/qqmllanguage/data/circularSingleton.qml new file mode 100644 index 0000000000..e569111956 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/circularSingleton.qml @@ -0,0 +1,6 @@ +import QtQuick 2.10 +import "singleton/circular" + +QtObject { + property int value: MySingleton.value +} diff --git a/tests/auto/qml/qqmllanguage/data/cppnamespace.qml b/tests/auto/qml/qqmllanguage/data/cppnamespace.qml index efedf2b14a..48f7eb6715 100644 --- a/tests/auto/qml/qqmllanguage/data/cppnamespace.qml +++ b/tests/auto/qml/qqmllanguage/data/cppnamespace.qml @@ -2,4 +2,5 @@ import Test 1.0 MyNamespacedType { myEnum: MyNamespace.Key5 + property int intProperty: MyNamespace.MyOtherNSEnum.OtherKey2 } diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/CustomMouseArea.qml b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomMouseArea.qml new file mode 100644 index 0000000000..f6ec5848c1 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomMouseArea.qml @@ -0,0 +1,6 @@ +import QtQuick 2.6 + +MouseArea { + +} + diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangle.qml b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangle.qml new file mode 100644 index 0000000000..b3fa43a671 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangle.qml @@ -0,0 +1,4 @@ +import QtQuick 2.6 + +Rectangle { +} diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangleWithProp.qml b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangleWithProp.qml new file mode 100644 index 0000000000..cf566b9315 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceOf/CustomRectangleWithProp.qml @@ -0,0 +1,6 @@ +import QtQuick 2.6 + +Rectangle { + property int somethingCustom: 0 +} + diff --git a/tests/auto/qml/qqmllanguage/data/instanceOf/qmldir b/tests/auto/qml/qqmllanguage/data/instanceOf/qmldir new file mode 100644 index 0000000000..144c93d8e3 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceOf/qmldir @@ -0,0 +1,2 @@ +CustomRectangle 1.0 CustomRectangle.qml +CustomMouseArea 1.0 CustomMouseArea.qml diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtqml.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml.qml new file mode 100644 index 0000000000..d74b172cf8 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml.qml @@ -0,0 +1,13 @@ +import QtQml 2.0 + +QtObject { + id: qtobjectInstance + + property Timer aTimer: Timer { + id: timerInstance + } + + property Connections aConnections: Connections { + id: connectionsInstance + } +} diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtqml_qualified.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml_qualified.qml new file mode 100644 index 0000000000..a8e303363e --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtqml_qualified.qml @@ -0,0 +1,13 @@ +import QtQml 2.0 as QmlImport + +QmlImport.QtObject { + id: qtobjectInstance + + property QmlImport.Timer aTimer: QmlImport.Timer { + id: timerInstance + } + + property QmlImport.Connections aConnections: QmlImport.Connections { + id: connectionsInstance + } +} diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtquick.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick.qml new file mode 100644 index 0000000000..9c1808d515 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + id: itemInstance + + Rectangle { + id: rectangleInstance + } + + MouseArea { + id: mouseAreaInstance + } +} + diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite.qml new file mode 100644 index 0000000000..78fc112805 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite.qml @@ -0,0 +1,26 @@ +import QtQuick 2.0 +import "instanceOf" + +Item { + id: itemInstance + + Rectangle { + id: rectangleInstance + } + + MouseArea { + id: mouseAreaInstance + } + + CustomRectangle { + id: customRectangleInstance + } + CustomRectangleWithProp { + id: customRectangleWithPropInstance + } + CustomMouseArea { + id: customMouseAreaInstance + } +} + + diff --git a/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite_qualified.qml b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite_qualified.qml new file mode 100644 index 0000000000..97361b7334 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/instanceof_qtquick_composite_qualified.qml @@ -0,0 +1,27 @@ +import QtQuick 2.0 as QuickImport +import "instanceOf" as CustomImport + +QuickImport.Item { + id: itemInstance + + QuickImport.Rectangle { + id: rectangleInstance + } + + QuickImport.MouseArea { + id: mouseAreaInstance + } + + CustomImport.CustomRectangle { + id: customRectangleInstance + } + CustomImport.CustomRectangleWithProp { + id: customRectangleWithPropInstance + } + CustomImport.CustomMouseArea { + id: customMouseAreaInstance + } +} + + + diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.errors.txt new file mode 100644 index 0000000000..a96fe376aa --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.errors.txt @@ -0,0 +1 @@ +6:22:Expected token `numeric literal' diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.qml b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.qml new file mode 100644 index 0000000000..fef23ecbef --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.1.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +QtObject { + enum MyEnum { + EnumValue1, + EnumValue2 = "hello", + EnumValue3 + } +} diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.errors.txt new file mode 100644 index 0000000000..a96fe376aa --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.errors.txt @@ -0,0 +1 @@ +6:22:Expected token `numeric literal' diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.qml b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.qml new file mode 100644 index 0000000000..9892fcd19c --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.2.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +QtObject { + enum MyEnum { + EnumValue1, + EnumValue2 = hello, + EnumValue3 + } +} diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.errors.txt new file mode 100644 index 0000000000..43465c60ec --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.errors.txt @@ -0,0 +1 @@ +7:22:Enum value out of range diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.qml b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.qml new file mode 100644 index 0000000000..654bc0e626 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.3.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +QtObject { + enum MyEnum { + EnumValue1, + EnumValue2, + EnumValue3 = 2147483648 + } +} diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.errors.txt b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.errors.txt new file mode 100644 index 0000000000..12756dc593 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.errors.txt @@ -0,0 +1 @@ +7:22:Enum value must be an integer diff --git a/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.qml b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.qml new file mode 100644 index 0000000000..4a0aafba5e --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/invalidQmlEnumValue.4.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +QtObject { + enum MyEnum { + EnumValue1, + EnumValue2, + EnumValue3 = 17.5 + } +} diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/NonSingletonType.qml b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/NonSingletonType.qml new file mode 100644 index 0000000000..ec7c76c055 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/NonSingletonType.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 +import org.qtproject.MixedModule 1.0 + +Item { +} diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml new file mode 100644 index 0000000000..7763c783f1 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/SingletonType.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 +pragma Singleton + +Item { +} diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/qmldir b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/qmldir new file mode 100644 index 0000000000..cd03a5f941 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/qmldir @@ -0,0 +1,4 @@ +module org.qtproject.MixedModule +singleton SingletonType 1.0 SingletonType.qml +NonSingletonType 1.0 NonSingletonType.qml +Test 1.0 test.js diff --git a/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/test.js b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/test.js new file mode 100644 index 0000000000..6a53b53b02 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/lib/org/qtproject/MixedModule/test.js @@ -0,0 +1 @@ +var foo = 1 diff --git a/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.errors.txt b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.errors.txt new file mode 100644 index 0000000000..d1bd2bcff4 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.errors.txt @@ -0,0 +1 @@ +6:9:Enum names must begin with an upper case letter diff --git a/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.qml b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.qml new file mode 100644 index 0000000000..0b50820128 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.1.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +QtObject { + enum MyEnum { + EnumValue1, + enumValue2, + EnumValue3 + } +} diff --git a/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.errors.txt b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.errors.txt new file mode 100644 index 0000000000..3e051c416e --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.errors.txt @@ -0,0 +1 @@ +4:5:Scoped enum names must begin with an upper case letter diff --git a/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.qml b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.qml new file mode 100644 index 0000000000..bb7aea6aa4 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/lowercaseQmlEnum.2.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +QtObject { + enum myEnum { + EnumValue1, + EnumValue2, + EnumValue3 + } +} diff --git a/tests/auto/qml/qqmllanguage/data/mixedModuleWithSelfImport.qml b/tests/auto/qml/qqmllanguage/data/mixedModuleWithSelfImport.qml new file mode 100644 index 0000000000..7768a6aedf --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/mixedModuleWithSelfImport.qml @@ -0,0 +1,3 @@ +import org.qtproject.MixedModule 1.0 + +NonSingletonType {} diff --git a/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyInternalType.qml b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyInternalType.qml new file mode 100644 index 0000000000..0e69012662 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyInternalType.qml @@ -0,0 +1,2 @@ +import QtQml 2.0 +QtObject {} diff --git a/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicType.qml b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicType.qml new file mode 100644 index 0000000000..c6b38d51a9 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicType.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + property InternalType myInternalType: InternalType {} +} diff --git a/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicTypeWithExplicitImport.qml b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicTypeWithExplicitImport.qml new file mode 100644 index 0000000000..9b488f92da --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/MyPublicTypeWithExplicitImport.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 +import modulewithinternaltypes 1.0 +QtObject { + property InternalType myInternalType: InternalType {} +} diff --git a/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/qmldir b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/qmldir new file mode 100644 index 0000000000..3593845329 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/modulewithinternaltypes/qmldir @@ -0,0 +1,3 @@ +PublicType 1.0 MyPublicType.qml +PublicTypeWithExplicitImport 1.0 MyPublicTypeWithExplicitImport.qml +internal InternalType MyInternalType.qml diff --git a/tests/auto/qml/qqmllanguage/data/registeredCompositeTypeWithEnum.qml b/tests/auto/qml/qqmllanguage/data/registeredCompositeTypeWithEnum.qml index 5f8c11e5f6..b6a07693f2 100644 --- a/tests/auto/qml/qqmllanguage/data/registeredCompositeTypeWithEnum.qml +++ b/tests/auto/qml/qqmllanguage/data/registeredCompositeTypeWithEnum.qml @@ -3,4 +3,5 @@ import Test 1.0 RegisteredCompositeTypeWithEnum { property int enumValue0: RegisteredCompositeTypeWithEnum.EnumValue0 property int enumValue42: RegisteredCompositeTypeWithEnum.EnumValue42 + property int enumValue15: RegisteredCompositeTypeWithEnum.ScopedCompositeEnum.EnumValue15 } diff --git a/tests/auto/qml/qqmllanguage/data/scopedEnum.qml b/tests/auto/qml/qqmllanguage/data/scopedEnum.qml new file mode 100644 index 0000000000..7f4177af76 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/scopedEnum.qml @@ -0,0 +1,21 @@ +import QtQuick 2.0 +import Test 1.0 + +MyTypeObject { + id: obj + scopedEnum: MyTypeObject.MyScopedEnum.ScopedVal1 + intProperty: MyTypeObject.MyScopedEnum.ScopedVal2 + property int listValue: myModel.get(0).myData + property int noScope: MyTypeObject.ScopedVal1 + + function assignNewValue() { + scopedEnum = MyTypeObject.MyScopedEnum.ScopedVal2 + noScope = MyTypeObject.ScopedVal2 + } + + property ListModel myModel: ListModel { + ListElement { + myData: MyTypeObject.MyScopedEnum.ScopedVal3 + } + } +} diff --git a/tests/auto/qml/qqmllanguage/data/scopedEnumList.errors.txt b/tests/auto/qml/qqmllanguage/data/scopedEnumList.errors.txt new file mode 100644 index 0000000000..67576dfd8d --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/scopedEnumList.errors.txt @@ -0,0 +1 @@ +7:13:ListElement: cannot use script for property value diff --git a/tests/auto/qml/qqmllanguage/data/scopedEnumList.qml b/tests/auto/qml/qqmllanguage/data/scopedEnumList.qml new file mode 100644 index 0000000000..8655139683 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/scopedEnumList.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 +import Test 1.0 + +MyTypeObject { + property ListModel myModel: ListModel { + ListElement { + myData: MyTypeObject.MyScopedEnum + } + } +} diff --git a/tests/auto/qml/qqmllanguage/data/singleton/circular/MySingleton.qml b/tests/auto/qml/qqmllanguage/data/singleton/circular/MySingleton.qml new file mode 100644 index 0000000000..1253018789 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/singleton/circular/MySingleton.qml @@ -0,0 +1,12 @@ +pragma Singleton +import QtQuick 2.10 + +QtObject { + enum MyEnum { + Value0, + Value1, + Value2 + } + + property int value: MySingleton.Value2 +} diff --git a/tests/auto/qml/qqmllanguage/data/singleton/circular/qmldir b/tests/auto/qml/qqmllanguage/data/singleton/circular/qmldir new file mode 100644 index 0000000000..3bc50738dd --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/singleton/circular/qmldir @@ -0,0 +1 @@ +singleton MySingleton MySingleton.qml diff --git a/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml b/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml new file mode 100644 index 0000000000..2509fc0df1 --- /dev/null +++ b/tests/auto/qml/qqmllanguage/data/usingTypeWithEnum.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +QtObject { + property int enumValue: TypeWithEnum.EnumValue2 + property int enumValue2: -1 + property int scopedEnumValue: TypeWithEnum.MyEnum.EnumValue3 + Component.onCompleted: enumValue2 = TypeWithEnum.EnumValue1 +} diff --git a/tests/auto/qml/qqmllanguage/qqmllanguage.pro b/tests/auto/qml/qqmllanguage/qqmllanguage.pro index 99c0c3e823..3e88f3f0db 100644 --- a/tests/auto/qml/qqmllanguage/qqmllanguage.pro +++ b/tests/auto/qml/qqmllanguage/qqmllanguage.pro @@ -6,7 +6,6 @@ SOURCES += tst_qqmllanguage.cpp \ testtypes.cpp HEADERS += testtypes.h -INCLUDEPATH += ../../shared/ HEADERS += ../../shared/testhttpserver.h SOURCES += ../../shared/testhttpserver.cpp diff --git a/tests/auto/qml/qqmllanguage/testtypes.cpp b/tests/auto/qml/qqmllanguage/testtypes.cpp index d2240d25a9..1a81528bc4 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.cpp +++ b/tests/auto/qml/qqmllanguage/testtypes.cpp @@ -136,7 +136,7 @@ void CustomBinding::componentComplete() QQmlContextData *context = QQmlContextData::get(qmlContext(this)); QQmlProperty property(m_target, name, qmlContext(this)); - QV4::Scope scope(QQmlEnginePrivate::getV4Engine(qmlEngine(this))); + QV4::Scope scope(qmlEngine(this)->handle()); QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(scope.engine->rootContext(), context, m_target)); QQmlBinding *qmlBinding = QQmlBinding::create(&QQmlPropertyPrivate::get(property)->core, compilationUnit->runtimeFunctions[bindingId], m_target, context, qmlContext); diff --git a/tests/auto/qml/qqmllanguage/testtypes.h b/tests/auto/qml/qqmllanguage/testtypes.h index d9ddff20a7..5025a6e7f2 100644 --- a/tests/auto/qml/qqmllanguage/testtypes.h +++ b/tests/auto/qml/qqmllanguage/testtypes.h @@ -223,6 +223,7 @@ class MyTypeObject : public QObject Q_PROPERTY(Qt::TextFormat qtEnumProperty READ qtEnumProperty WRITE setQtEnumProperty NOTIFY qtEnumPropertyChanged) Q_PROPERTY(MyMirroredEnum mirroredEnumProperty READ mirroredEnumProperty WRITE setMirroredEnumProperty NOTIFY mirroredEnumPropertyChanged) Q_PROPERTY(MyEnumContainer::RelatedEnum relatedEnumProperty READ relatedEnumProperty WRITE setRelatedEnumProperty) + Q_PROPERTY(MyScopedEnum scopedEnum READ scopedEnum WRITE setScopedEnum) Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringPropertyChanged) Q_PROPERTY(QByteArray byteArrayProperty READ byteArrayProperty WRITE setByteArrayProperty NOTIFY byteArrayPropertyChanged) Q_PROPERTY(uint uintProperty READ uintProperty WRITE setUintProperty NOTIFY uintPropertyChanged) @@ -339,6 +340,14 @@ public: relatedEnumPropertyValue = v; } + enum class MyScopedEnum : int { ScopedVal1, ScopedVal2, ScopedVal3 }; + Q_ENUM(MyScopedEnum) + MyScopedEnum scopedEnumPropertyValue; + MyScopedEnum scopedEnum() const { return scopedEnumPropertyValue; } + void setScopedEnum(MyScopedEnum v) { + scopedEnumPropertyValue = v; + } + QString stringPropertyValue; QString stringProperty() const { return stringPropertyValue; @@ -738,6 +747,13 @@ namespace MyNamespace { }; Q_ENUM_NS(MyNSEnum); + enum class MyOtherNSEnum { + OtherKey1 = 1, + OtherKey2 + }; + Q_ENUM_NS(MyOtherNSEnum); + + class MyNamespacedType : public QObject { Q_OBJECT @@ -1171,9 +1187,11 @@ class MyCompositeBaseType : public QObject { Q_OBJECT Q_ENUMS(CompositeEnum) + Q_ENUMS(ScopedCompositeEnum) public: enum CompositeEnum { EnumValue0, EnumValue42 = 42 }; + enum class ScopedCompositeEnum : int { EnumValue15 = 15 }; static QObject *qmlAttachedProperties(QObject *parent) { return new QObject(parent); } }; diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index 83151fb6e2..03d53b755d 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -179,6 +179,8 @@ private slots: void importIncorrectCase(); void importJs_data(); void importJs(); + void explicitSelfImport(); + void importInternalType(); void qmlAttachedPropertiesObjectMethod(); void customOnProperty(); @@ -209,6 +211,8 @@ private slots: void lowercaseEnumRuntime(); void lowercaseEnumCompileTime_data(); void lowercaseEnumCompileTime(); + void scopedEnum(); + void qmlEnums(); void literals_data(); void literals(); @@ -237,6 +241,7 @@ private slots: void compositeSingletonJavaScriptPragma(); void compositeSingletonSelectors(); void compositeSingletonRegistered(); + void compositeSingletonCircular(); void customParserBindingScopes(); void customParserEvaluateEnum(); @@ -267,6 +272,9 @@ private slots: void qmlTypeCanBeResolvedByName_data(); void qmlTypeCanBeResolvedByName(); + void instanceof_data(); + void instanceof(); + void concurrentLoadQmlDir(); void accessDeletedObject(); @@ -319,7 +327,7 @@ private: if (!errorfile) { \ if (qgetenv("DEBUG") != "" && !component.errors().isEmpty()) \ qWarning() << "Unexpected Errors:" << component.errors(); \ - QVERIFY(!component.isError()); \ + QVERIFY2(!component.isError(), qPrintable(component.errorString())); \ QVERIFY(component.errors().isEmpty()); \ } else { \ DETERMINE_ERRORS(errorfile,expected,actual);\ @@ -550,6 +558,14 @@ void tst_qqmllanguage::errors_data() QTest::newRow("singularProperty") << "singularProperty.qml" << "singularProperty.errors.txt" << false; QTest::newRow("singularProperty.2") << "singularProperty.2.qml" << "singularProperty.2.errors.txt" << false; + QTest::newRow("scopedEnumList") << "scopedEnumList.qml" << "scopedEnumList.errors.txt" << false; + QTest::newRow("lowercase enum value") << "lowercaseQmlEnum.1.qml" << "lowercaseQmlEnum.1.errors.txt" << false; + QTest::newRow("lowercase enum type") << "lowercaseQmlEnum.2.qml" << "lowercaseQmlEnum.2.errors.txt" << false; + QTest::newRow("string enum value") << "invalidQmlEnumValue.1.qml" << "invalidQmlEnumValue.1.errors.txt" << false; + QTest::newRow("identifier enum type") << "invalidQmlEnumValue.2.qml" << "invalidQmlEnumValue.2.errors.txt" << false; + QTest::newRow("enum value too large") << "invalidQmlEnumValue.3.qml" << "invalidQmlEnumValue.3.errors.txt" << false; + QTest::newRow("non-integer enum value") << "invalidQmlEnumValue.4.qml" << "invalidQmlEnumValue.4.errors.txt" << false; + const QString expectedError = isCaseSensitiveFileSystem(dataDirectory()) ? QStringLiteral("incorrectCase.errors.sensitive.txt") : QStringLiteral("incorrectCase.errors.insensitive.txt"); @@ -1610,6 +1626,9 @@ void tst_qqmllanguage::cppnamespace() VERIFY_ERRORS(0); QObject *object = component.create(); QVERIFY(object != 0); + + QCOMPARE(object->property("intProperty").toInt(), (int)MyNamespace::MyOtherNSEnum::OtherKey2); + delete object; } @@ -3068,12 +3087,45 @@ void tst_qqmllanguage::importJs() engine.setImportPathList(defaultImportPathList); } +void tst_qqmllanguage::explicitSelfImport() +{ + engine.setImportPathList(QStringList(defaultImportPathList) << testFile("lib")); + + QQmlComponent component(&engine, testFileUrl("mixedModuleWithSelfImport.qml")); + QVERIFY(component.errors().count() == 0); + + engine.setImportPathList(defaultImportPathList); +} + +void tst_qqmllanguage::importInternalType() +{ + QQmlEngine engine; + engine.addImportPath(dataDirectory()); + + { + QQmlComponent component(&engine); + component.setData("import modulewithinternaltypes 1.0\nPublicType{}", QUrl()); + VERIFY_ERRORS(0); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QVERIFY(obj->property("myInternalType").value<QObject*>() != 0); + } + { + QQmlComponent component(&engine); + component.setData("import modulewithinternaltypes 1.0\nPublicTypeWithExplicitImport{}", QUrl()); + VERIFY_ERRORS(0); + QScopedPointer<QObject> obj(component.create()); + QVERIFY(!obj.isNull()); + QVERIFY(obj->property("myInternalType").value<QObject*>() != 0); + } +} + void tst_qqmllanguage::qmlAttachedPropertiesObjectMethod() { QObject object; QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(&object, false), (QObject *)0); - QCOMPARE(qmlAttachedPropertiesObject<MyQmlObject>(&object, true), (QObject *)0); + QVERIFY(qmlAttachedPropertiesObject<MyQmlObject>(&object, true)); { QQmlComponent component(&engine, testFileUrl("qmlAttachedPropertiesObjectMethod.1.qml")); @@ -3510,6 +3562,7 @@ void tst_qqmllanguage::registeredCompositeTypeWithEnum() QCOMPARE(o->property("enumValue0").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue0)); QCOMPARE(o->property("enumValue42").toInt(), static_cast<int>(MyCompositeBaseType::EnumValue42)); + QCOMPARE(o->property("enumValue15").toInt(), static_cast<int>(MyCompositeBaseType::ScopedCompositeEnum::EnumValue15)); delete o; } @@ -3690,6 +3743,50 @@ void tst_qqmllanguage::lowercaseEnumCompileTime() VERIFY_ERRORS(qPrintable(errorFile)); } +void tst_qqmllanguage::scopedEnum() +{ + QQmlComponent component(&engine, testFileUrl("scopedEnum.qml")); + + MyTypeObject *o = qobject_cast<MyTypeObject *>(component.create()); + QVERIFY(o != 0); + + QCOMPARE(o->scopedEnum(), MyTypeObject::MyScopedEnum::ScopedVal1); + QCOMPARE(o->intProperty(), (int)MyTypeObject::MyScopedEnum::ScopedVal2); + QCOMPARE(o->property("listValue").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal3); + QCOMPARE(o->property("noScope").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal1); + + QMetaObject::invokeMethod(o, "assignNewValue"); + QCOMPARE(o->scopedEnum(), MyTypeObject::MyScopedEnum::ScopedVal2); + QCOMPARE(o->property("noScope").toInt(), (int)MyTypeObject::MyScopedEnum::ScopedVal2); +} + +void tst_qqmllanguage::qmlEnums() +{ + { + QQmlComponent component(&engine, testFileUrl("TypeWithEnum.qml")); + QObject *o = component.create(); + QVERIFY(o); + QCOMPARE(o->property("enumValue").toInt(), 1); + QCOMPARE(o->property("enumValue2").toInt(), 2); + QCOMPARE(o->property("scopedEnumValue").toInt(), 1); + + QCOMPARE(o->property("otherEnumValue1").toInt(), 24); + QCOMPARE(o->property("otherEnumValue2").toInt(), 25); + QCOMPARE(o->property("otherEnumValue3").toInt(), 24); + QCOMPARE(o->property("otherEnumValue4").toInt(), 25); + QCOMPARE(o->property("otherEnumValue5").toInt(), 1); + } + + { + QQmlComponent component(&engine, testFileUrl("usingTypeWithEnum.qml")); + QObject *o = component.create(); + QVERIFY(o); + QCOMPARE(o->property("enumValue").toInt(), 1); + QCOMPARE(o->property("enumValue2").toInt(), 0); + QCOMPARE(o->property("scopedEnumValue").toInt(), 2); + } +} + void tst_qqmllanguage::literals_data() { QTest::addColumn<QString>("property"); @@ -4123,6 +4220,22 @@ void tst_qqmllanguage::compositeSingletonRegistered() verifyCompositeSingletonPropertyValues(o, "value1", 925, "value2", 755); } +void tst_qqmllanguage::compositeSingletonCircular() +{ + QQmlComponent component(&engine, testFile("circularSingleton.qml")); + VERIFY_ERRORS(0); + + QQmlTestMessageHandler messageHandler; + + QObject *o = component.create(); + QVERIFY(o != 0); + + // ensure we aren't hitting the recursion warning + QVERIFY2(messageHandler.messages().isEmpty(), qPrintable(messageHandler.messageString())); + + QCOMPARE(o->property("value").toInt(), 2); +} + void tst_qqmllanguage::customParserBindingScopes() { QQmlComponent component(&engine, testFile("customParserBindingScopes.qml")); @@ -4562,6 +4675,200 @@ void tst_qqmllanguage::qmlTypeCanBeResolvedByName() QVERIFY(!o.isNull()); } +// Tests for the QML-only extensions of instanceof. Tests for the regular JS +// instanceof belong in tst_qqmlecmascript! +void tst_qqmllanguage::instanceof_data() +{ + QTest::addColumn<QUrl>("documentToTestIn"); + QTest::addColumn<QVariant>("expectedValue"); + + // so the way this works is that the name of the test tag defines the test + // to run. + // + // the expectedValue is either a boolean true or false for whether the two + // operands are indeed an instanceof each other, or a string for the + // expected error message. + + // assert that basic types don't convert to QObject + QTest::newRow("1 instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + QTest::newRow("true instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + QTest::newRow("\"foobar\" instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + + // assert that Managed don't either + QTest::newRow("new String(\"foobar\") instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + QTest::newRow("new Object() instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + QTest::newRow("new Date() instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant("TypeError: Type error"); + + // test that simple QtQml comparisons work + QTest::newRow("qtobjectInstance instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(true); + QTest::newRow("qtobjectInstance instanceof Timer") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(false); + QTest::newRow("timerInstance instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(true); + QTest::newRow("timerInstance instanceof Timer") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(true); + QTest::newRow("connectionsInstance instanceof QtObject") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(true); + QTest::newRow("connectionsInstance instanceof Timer") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(false); + QTest::newRow("connectionsInstance instanceof Connections") + << testFileUrl("instanceof_qtqml.qml") + << QVariant(true); + + // make sure they still work when imported with a qualifier + QTest::newRow("qtobjectInstance instanceof QmlImport.QtObject") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(true); + QTest::newRow("qtobjectInstance instanceof QmlImport.Timer") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(false); + QTest::newRow("timerInstance instanceof QmlImport.QtObject") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(true); + QTest::newRow("timerInstance instanceof QmlImport.Timer") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(true); + QTest::newRow("connectionsInstance instanceof QmlImport.QtObject") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(true); + QTest::newRow("connectionsInstance instanceof QmlImport.Timer") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(false); + QTest::newRow("connectionsInstance instanceof QmlImport.Connections") + << testFileUrl("instanceof_qtqml_qualified.qml") + << QVariant(true); + + // test that Quick C++ types work ok + QTest::newRow("itemInstance instanceof QtObject") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(true); + QTest::newRow("itemInstance instanceof Timer") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(false); + QTest::newRow("itemInstance instanceof Rectangle") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(false); + QTest::newRow("rectangleInstance instanceof Item") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(true); + QTest::newRow("rectangleInstance instanceof Rectangle") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(true); + QTest::newRow("rectangleInstance instanceof MouseArea") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(false); + QTest::newRow("mouseAreaInstance instanceof Item") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(true); + QTest::newRow("mouseAreaInstance instanceof Rectangle") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(false); + QTest::newRow("mouseAreaInstance instanceof MouseArea") + << testFileUrl("instanceof_qtquick.qml") + << QVariant(true); + + // test that unqualified quick composite types work ok + QTest::newRow("rectangleInstance instanceof CustomRectangle") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(false); + QTest::newRow("customRectangleInstance instanceof Rectangle") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(true); + QTest::newRow("customRectangleInstance instanceof Item") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(true); + QTest::newRow("customRectangleWithPropInstance instanceof CustomRectangleWithProp") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(true); + QTest::newRow("customRectangleWithPropInstance instanceof CustomRectangle") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(false); // ### XXX: QTBUG-58477 + QTest::newRow("customRectangleWithPropInstance instanceof Rectangle") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(true); + QTest::newRow("customRectangleInstance instanceof MouseArea") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(false); + QTest::newRow("customMouseAreaInstance instanceof MouseArea") + << testFileUrl("instanceof_qtquick_composite.qml") + << QVariant(true); + + // test that they still work when qualified + QTest::newRow("rectangleInstance instanceof CustomImport.CustomRectangle") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(false); + QTest::newRow("customRectangleInstance instanceof QuickImport.Rectangle") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(true); + QTest::newRow("customRectangleInstance instanceof QuickImport.Item") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(true); + QTest::newRow("customRectangleWithPropInstance instanceof CustomImport.CustomRectangleWithProp") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(true); + QTest::newRow("customRectangleWithPropInstance instanceof CustomImport.CustomRectangle") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(false); // ### XXX: QTBUG-58477 + QTest::newRow("customRectangleWithPropInstance instanceof QuickImport.Rectangle") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(true); + QTest::newRow("customRectangleInstance instanceof QuickImport.MouseArea") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(false); + QTest::newRow("customMouseAreaInstance instanceof QuickImport.MouseArea") + << testFileUrl("instanceof_qtquick_composite_qualified.qml") + << QVariant(true); +} + +void tst_qqmllanguage::instanceof() +{ + QFETCH(QUrl, documentToTestIn); + QFETCH(QVariant, expectedValue); + + QQmlEngine engine; + QQmlComponent component(&engine, documentToTestIn); + VERIFY_ERRORS(0); + + QScopedPointer<QObject> o(component.create()); + QVERIFY(o != 0); + + QQmlExpression expr(engine.contextForObject(o.data()), 0, QString::fromLatin1(QTest::currentDataTag())); + QVariant ret = expr.evaluate(); + + if (expectedValue.type() == QVariant::Bool) { + // no error expected + QVERIFY2(!expr.hasError(), qPrintable(expr.error().description())); + bool returnValue = ret.toBool(); + + if (QTest::currentDataTag() == QLatin1String("customRectangleWithPropInstance instanceof CustomRectangle") || + QTest::currentDataTag() == QLatin1String("customRectangleWithPropInstance instanceof CustomImport.CustomRectangle")) + QEXPECT_FAIL("", "QTBUG-58477: QML type rules are a little lax", Continue); + QCOMPARE(returnValue, expectedValue.toBool()); + } else { + QVERIFY(expr.hasError()); + QCOMPARE(expr.error().description(), expectedValue.toString()); + } +} + void tst_qqmllanguage::concurrentLoadQmlDir() { ThreadedTestHTTPServer server(dataDirectory()); diff --git a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp index f5c0e5ddf7..73aec7c55b 100644 --- a/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp +++ b/tests/auto/qml/qqmllistmodel/tst_qqmllistmodel.cpp @@ -124,6 +124,7 @@ private slots: void modify_through_delegate(); void bindingsOnGetResult(); void stringifyModelEntry(); + void qobjectTrackerForDynamicModelObjects(); }; bool tst_qqmllistmodel::compareVariantList(const QVariantList &testList, QVariant object) @@ -1205,8 +1206,8 @@ void tst_qqmllistmodel::role_mode_data() QTest::newRow("default1") << "{append({'a':1});dynamicRoles}" << 0 << ""; QTest::newRow("enableDynamic0") << "{dynamicRoles=true;dynamicRoles}" << 1 << ""; - QTest::newRow("enableDynamic1") << "{append({'a':1});dynamicRoles=true;dynamicRoles}" << 0 << "<Unknown File>: QML ListModel: unable to enable dynamic roles as this model is not empty!"; - QTest::newRow("enableDynamic2") << "{dynamicRoles=true;append({'a':1});dynamicRoles=false;dynamicRoles}" << 1 << "<Unknown File>: QML ListModel: unable to enable static roles as this model is not empty!"; + QTest::newRow("enableDynamic1") << "{append({'a':1});dynamicRoles=true;dynamicRoles}" << 0 << "<Unknown File>: QML ListModel: unable to enable dynamic roles as this model is not empty"; + QTest::newRow("enableDynamic2") << "{dynamicRoles=true;append({'a':1});dynamicRoles=false;dynamicRoles}" << 1 << "<Unknown File>: QML ListModel: unable to enable static roles as this model is not empty"; } void tst_qqmllistmodel::role_mode() @@ -1505,6 +1506,33 @@ void tst_qqmllistmodel::stringifyModelEntry() QCOMPARE(v.toString(), expectedString); } +void tst_qqmllistmodel::qobjectTrackerForDynamicModelObjects() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData( + "import QtQuick 2.0\n" + "Item {\n" + " ListModel {\n" + " id: testModel\n" + " objectName: \"testModel\"\n" + " ListElement { name: \"Joe\"; age: 22 }\n" + " }\n" + "}\n", QUrl()); + QScopedPointer<QObject> scene(component.create()); + QQmlListModel *model = scene->findChild<QQmlListModel*>("testModel"); + QQmlExpression expr(engine.rootContext(), model, "get(0);"); + QVariant v = expr.evaluate(); + QVERIFY2(!expr.hasError(), QTest::toString(expr.error().toString())); + + QObject *obj = v.value<QObject*>(); + QVERIFY(obj); + + QQmlData *ddata = QQmlData::get(obj, /*create*/false); + QVERIFY(ddata); + QVERIFY(!ddata->jsWrapper.isNullOrUndefined()); +} + QTEST_MAIN(tst_qqmllistmodel) #include "tst_qqmllistmodel.moc" diff --git a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp index 9564d6a8b2..6301c35676 100644 --- a/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp +++ b/tests/auto/qml/qqmllistmodelworkerscript/tst_qqmllistmodelworkerscript.cpp @@ -192,7 +192,7 @@ void tst_qqmllistmodelworkerscript::dynamic_data() QTest::addColumn<QString>("warning"); QTest::addColumn<bool>("dynamicRoles"); - for (int i=0 ; i < 2 ; ++i) { + for (int i = 0; i < 2; ++i) { bool dr = (i != 0); // Simple flat model @@ -434,7 +434,7 @@ void tst_qqmllistmodelworkerscript::get_data() QTest::addColumn<QVariant>("roleValue"); QTest::addColumn<bool>("dynamicRoles"); - for (int i=0 ; i < 2 ; ++i) { + for (int i =0; i < 2; ++i) { bool dr = (i != 0); QTest::newRow("simple value") << "get(0).roleA = 500" << 0 << "roleA" << QVariant(500) << dr; @@ -515,7 +515,7 @@ void tst_qqmllistmodelworkerscript::property_changes_data() QTest::addColumn<QString>("testExpression"); QTest::addColumn<bool>("dynamicRoles"); - for (int i=0 ; i < 2 ; ++i) { + for (int i=1 ; i < 2 ; ++i) { bool dr = (i != 0); QTest::newRow("set: plain") << "append({'a':123, 'b':456, 'c':789});" << "set(0,{'b':123});" @@ -574,7 +574,7 @@ void tst_qqmllistmodelworkerscript::property_changes_data() << "b" << 0 << true << "get(0).b.get(0).a == 1 && get(0).b.get(1).a == 2 && get(0).b.get(2).a == 3" << dr; QTest::newRow("nested-set: list, no changes, empty") << "append({'a':123, 'b':[], 'c':789});" << "set(0,{'b':[]});" - << "b" << 0 << true << "get(0).b.count == 0" << dr; + << "b" << 0 << false << "get(0).b.count == 0" << dr; } } diff --git a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp index d0ce83b997..4f4deaafe5 100644 --- a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp +++ b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp @@ -1268,8 +1268,8 @@ void tst_qqmllocale::timeZoneUpdated() { QByteArray original(qgetenv("TZ")); - // Set the timezone to Brisbane time - setTimeZone(QByteArray("AEST-10:00")); + // Set the timezone to Brisbane time, AEST-10:00 + setTimeZone(QByteArray("Australia/Brisbane")); DateFormatter formatter; @@ -1281,8 +1281,8 @@ void tst_qqmllocale::timeZoneUpdated() QVERIFY(obj); QVERIFY(obj->property("success").toBool()); - // Change to Indian time - setTimeZone(QByteArray("IST-05:30")); + // Change to Indian time, IST-05:30 + setTimeZone(QByteArray("Asia/Kolkata")); QMetaObject::invokeMethod(obj.data(), "check"); diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro deleted file mode 100644 index 150f2f08d3..0000000000 --- a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/invalidStrictModule.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = lib -CONFIG += plugin -SOURCES = plugin.cpp -QT = core qml -DESTDIR = ../imports/org/qtproject/InvalidStrictModule - -QT += core-private gui-private qml-private - -IMPORT_FILES = \ - qmldir - -include (../../../shared/imports.pri) diff --git a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir b/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir deleted file mode 100644 index 20716dc9f9..0000000000 --- a/tests/auto/qml/qqmlmoduleplugin/invalidStrictModule/qmldir +++ /dev/null @@ -1,2 +0,0 @@ -module org.qtproject.InvalidStrictModule -plugin invalidStrictModule diff --git a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro index 0f548aa6f8..ae13a041cc 100644 --- a/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro +++ b/tests/auto/qml/qqmlmoduleplugin/qqmlmoduleplugin.pro @@ -11,7 +11,6 @@ SUBDIRS =\ nestedPlugin\ strictModule\ strictModule.2\ - invalidStrictModule\ nonstrictModule\ preemptiveModule\ preemptedStrictModule\ diff --git a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp index 9abff7b2f6..85e4918b61 100644 --- a/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp +++ b/tests/auto/qml/qqmlmoduleplugin/tst_qqmlmoduleplugin.cpp @@ -580,12 +580,6 @@ void tst_qqmlmoduleplugin::importStrictModule_data() << QString() << QString(); - QTest::newRow("wrong target") - << "import org.qtproject.InvalidStrictModule 1.0\n" - "MyPluginType {}" - << QString() - << ":1:1: plugin cannot be loaded for module \"org.qtproject.InvalidStrictModule\": Cannot install element 'MyPluginType' into unregistered namespace 'org.qtproject.SomeOtherModule'"; - QTest::newRow("non-strict clash") << "import org.qtproject.NonstrictModule 1.0\n" "MyPluginType {}" diff --git a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp index beb60925bb..88a5d41975 100644 --- a/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp +++ b/tests/auto/qml/qqmlnotifier/tst_qqmlnotifier.cpp @@ -98,7 +98,7 @@ public: } protected: - void connectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE { + void connectNotify(const QMetaMethod &signal) override { if (signal.name() == "qmlObjectPropChanged") qmlObjectPropConnections++; if (signal.name() == "cppObjectPropChanged") cppObjectPropConnections++; if (signal.name() == "unboundPropChanged") unboundPropConnections++; @@ -112,7 +112,7 @@ protected: //qDebug() << Q_FUNC_INFO << this << signal.name(); } - void disconnectNotify(const QMetaMethod &signal) Q_DECL_OVERRIDE { + void disconnectNotify(const QMetaMethod &signal) override { if (signal.name() == "qmlObjectPropChanged") qmlObjectPropConnections--; if (signal.name() == "cppObjectPropChanged") cppObjectPropConnections--; if (signal.name() == "unboundPropChanged") unboundPropConnections--; @@ -146,7 +146,7 @@ public: {} private slots: - void initTestCase() Q_DECL_OVERRIDE; + void initTestCase() override; void cleanupTestCase(); void testConnectNotify(); diff --git a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp index 0576650d01..0bc1127069 100644 --- a/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp +++ b/tests/auto/qml/qqmlqt/tst_qqmlqt.cpp @@ -888,7 +888,8 @@ void tst_qqmlqt::dateTimeFormattingVariants_data() QTest::newRow("formatTime, qtime") << "formatTime" << QVariant::fromValue(time) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz")); QDate date(2011,5,31); - temporary = QDateTime(date); + // V4 reads the date in UTC but DateObject::toQDateTime() gives it back in local time: + temporary = QDateTime(date, QTime(0, 0, 0), Qt::UTC).toLocalTime(); QTest::newRow("formatDate, qdate") << "formatDate" << QVariant::fromValue(date) << (QStringList() << temporary.date().toString(Qt::DefaultLocaleShortDate) << temporary.date().toString(Qt::DefaultLocaleLongDate) << temporary.date().toString("ddd MMMM d yy")); QTest::newRow("formatDateTime, qdate") << "formatDateTime" << QVariant::fromValue(date) << (QStringList() << temporary.toString(Qt::DefaultLocaleShortDate) << temporary.toString(Qt::DefaultLocaleLongDate) << temporary.toString("M/d/yy H:m:s a")); QTest::newRow("formatTime, qdate") << "formatTime" << QVariant::fromValue(date) << (QStringList() << temporary.time().toString(Qt::DefaultLocaleShortDate) << temporary.time().toString(Qt::DefaultLocaleLongDate) << temporary.time().toString("H:m:s a") << temporary.time().toString("hh:mm:ss.zzz")); @@ -997,7 +998,7 @@ void tst_qqmlqt::exit() QSignalSpy spy(&engine, &QQmlEngine::exit); QObject *object = component.create(); - QVERIFY(object != Q_NULLPTR); + QVERIFY(object != nullptr); QCOMPARE(spy.count(), 1); QList<QVariant> arguments = spy.takeFirst(); QVERIFY(arguments.at(0).toInt() == object->property("returnCode").toInt()); diff --git a/tests/auto/qml/qqmltranslation/data/TranslationChangeBase.qml b/tests/auto/qml/qqmltranslation/data/TranslationChangeBase.qml new file mode 100644 index 0000000000..c447c84987 --- /dev/null +++ b/tests/auto/qml/qqmltranslation/data/TranslationChangeBase.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 + +QtObject { + property string baseProperty: qsTr("translate me"); +} diff --git a/tests/auto/qml/qqmltranslation/data/translationChange.qml b/tests/auto/qml/qqmltranslation/data/translationChange.qml new file mode 100644 index 0000000000..23b87c2493 --- /dev/null +++ b/tests/auto/qml/qqmltranslation/data/translationChange.qml @@ -0,0 +1,10 @@ +import QtQml 2.0 + +TranslationChangeBase { + baseProperty: "do not translate" + property string text1: qsTr("translate me") + function weDoTranslations() { + return qsTr("translate me") + } + property string text2: weDoTranslations() +} diff --git a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp index dd4edeb97d..80c54bdf8e 100644 --- a/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp +++ b/tests/auto/qml/qqmltranslation/tst_qqmltranslation.cpp @@ -44,6 +44,7 @@ private slots: void translation_data(); void translation(); void idTranslation(); + void translationChange(); }; void tst_qqmltranslation::translation_data() @@ -162,6 +163,51 @@ void tst_qqmltranslation::idTranslation() delete object; } +class DummyTranslator : public QTranslator +{ + Q_OBJECT + + QString translate(const char *context, const char *sourceText, const char *disambiguation, int n) const override + { + Q_UNUSED(context); + Q_UNUSED(disambiguation); + Q_UNUSED(n); + if (!qstrcmp(sourceText, "translate me")) + return QString::fromUtf8("xxx"); + return QString(); + } + + bool isEmpty() const override + { + return false; + } +}; + +void tst_qqmltranslation::translationChange() +{ + QQmlEngine engine; + + QQmlComponent component(&engine, testFileUrl("translationChange.qml")); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QCOMPARE(object->property("baseProperty").toString(), QString::fromUtf8("do not translate")); + QCOMPARE(object->property("text1").toString(), QString::fromUtf8("translate me")); + QCOMPARE(object->property("text2").toString(), QString::fromUtf8("translate me")); + + DummyTranslator translator; + QCoreApplication::installTranslator(&translator); + + QEvent ev(QEvent::LanguageChange); + QCoreApplication::sendEvent(&engine, &ev); + + QCOMPARE(object->property("baseProperty").toString(), QString::fromUtf8("do not translate")); + QCOMPARE(object->property("text1").toString(), QString::fromUtf8("xxx")); + QCOMPARE(object->property("text2").toString(), QString::fromUtf8("xxx")); + + QCoreApplication::removeTranslator(&translator); +} + QTEST_MAIN(tst_qqmltranslation) #include "tst_qqmltranslation.moc" diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.expect b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.expect Binary files differnew file mode 100644 index 0000000000..6d34e1d2bb --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.expect diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.qml b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.qml new file mode 100644 index 0000000000..ba9761201e --- /dev/null +++ b/tests/auto/qml/qqmlxmlhttprequest/data/send_data.11.qml @@ -0,0 +1,23 @@ +import QtQuick 2.0 + +QtObject { + property string url + + property bool dataOK: false + + Component.onCompleted: { + var x = new XMLHttpRequest; + x.open("POST", url); + x.setRequestHeader("Accept-Language","en-US"); + + // Test to the end + x.onreadystatechange = function() { + if (x.readyState == XMLHttpRequest.DONE) { + dataOK = (x.responseText == "QML Rocks!\n"); + } + } + + var data = new Uint8Array([1, 2, 3, 0, 3, 2, 1]) + x.send(data.buffer); + } +} diff --git a/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro b/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro index 44b2963918..572ab1d572 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro +++ b/tests/auto/qml/qqmlxmlhttprequest/qqmlxmlhttprequest.pro @@ -2,7 +2,6 @@ CONFIG += testcase TARGET = tst_qqmlxmlhttprequest macx:CONFIG -= app_bundle -INCLUDEPATH += ../../shared/ HEADERS += ../../shared/testhttpserver.h SOURCES += tst_qqmlxmlhttprequest.cpp \ diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp index 1ce07ecdab..59716acc0d 100644 --- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp +++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp @@ -291,7 +291,7 @@ class TestThreadedHTTPServer : public QObject Q_OBJECT public: TestThreadedHTTPServer(const QUrl &expectUrl, const QUrl &replyUrl, const QUrl &bodyUrl) - : m_server(Q_NULLPTR) { + : m_server(nullptr) { QMutexLocker locker(&m_lock); moveToThread(&m_thread); m_thread.start(); @@ -597,6 +597,7 @@ void tst_qqmlxmlhttprequest::send_withdata_data() QTest::newRow("Incorrect content-type - out of order") << "send_data.4.expect" << "send_data.5.qml"; QTest::newRow("PUT") << "send_data.6.expect" << "send_data.6.qml"; QTest::newRow("Correct content-type - no charset") << "send_data.1.expect" << "send_data.7.qml"; + QTest::newRow("ArrayBuffer") << "send_data.11.expect" << "send_data.11.qml"; } void tst_qqmlxmlhttprequest::send_options() diff --git a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp index f19e82032a..1a23286ede 100644 --- a/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp +++ b/tests/auto/qml/qquickfolderlistmodel/tst_qquickfolderlistmodel.cpp @@ -42,6 +42,7 @@ // From qquickfolderlistmodel.h const int FileNameRole = Qt::UserRole+1; enum SortField { Unsorted, Name, Time, Size, Type }; +enum Status { Null, Ready, Loading }; class tst_qquickfolderlistmodel : public QQmlDataTest { @@ -58,6 +59,7 @@ public slots: private slots: void initTestCase(); void basicProperties(); + void status(); void showFiles(); void resetFiltering(); void nameFilters(); @@ -141,6 +143,20 @@ void tst_qquickfolderlistmodel::basicProperties() QCOMPARE(flm->property("folder").toUrl(), QUrl::fromLocalFile("")); } +void tst_qquickfolderlistmodel::status() +{ + QQmlComponent component(&engine, testFileUrl("basic.qml")); + checkNoErrors(component); + + QAbstractListModel *flm = qobject_cast<QAbstractListModel*>(component.create()); + QVERIFY(flm != 0); + QTRY_COMPARE(flm->property("status").toInt(), int(Ready)); + flm->setProperty("folder", QUrl::fromLocalFile("")); + QTRY_COMPARE(flm->property("status").toInt(), int(Null)); + flm->setProperty("folder", QUrl::fromLocalFile(QDir::currentPath())); + QTRY_COMPARE(flm->property("status").toInt(), int(Ready)); +} + void tst_qquickfolderlistmodel::showFiles() { QQmlComponent component(&engine, testFileUrl("basic.qml")); diff --git a/tests/auto/qml/qwidgetsinqml/qwidgetsinqml.pro b/tests/auto/qml/qwidgetsinqml/qwidgetsinqml.pro new file mode 100644 index 0000000000..c86365d5ea --- /dev/null +++ b/tests/auto/qml/qwidgetsinqml/qwidgetsinqml.pro @@ -0,0 +1,7 @@ +CONFIG += testcase +CONFIG += parallel_test +TARGET = tst_qwidgetsinqml +macos:CONFIG -= app_bundle +QT += qml widgets testlib gui-private +SOURCES += tst_qwidgetsinqml.cpp +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 diff --git a/tests/auto/qml/qwidgetsinqml/tst_qwidgetsinqml.cpp b/tests/auto/qml/qwidgetsinqml/tst_qwidgetsinqml.cpp new file mode 100644 index 0000000000..c7bbb55474 --- /dev/null +++ b/tests/auto/qml/qwidgetsinqml/tst_qwidgetsinqml.cpp @@ -0,0 +1,283 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module 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 <QtTest/QtTest> +#include <QQmlEngine> +#include <QtQml> +#include <QWidget> + +class tst_QWidgetsInQml : public QObject +{ + Q_OBJECT +public: + tst_QWidgetsInQml(); + +private slots: + void instantiateWidget(); + void instantiateWidgetWithoutParentWidget(); + void widgetAsDefaultPropertyCollected(); + void widgetAsDefaultPropertyKept(); + void widgetAsDefaultPropertyKeptDuringCreation(); +}; + +static void gc(QQmlEngine &engine) +{ + engine.collectGarbage(); + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::processEvents(); +} + +// Like QtObject, but with default property +class QObjectContainer : public QObject +{ + Q_OBJECT + Q_CLASSINFO("DefaultProperty", "data"); + Q_PROPERTY(QQmlListProperty<QObject> data READ data DESIGNABLE false); +public: + QObjectContainer() + : widgetParent(0) + , gcOnAppend(false) + {} + + QQmlListProperty<QObject> data() { + return QQmlListProperty<QObject>(this, 0, children_append, children_count, children_at, children_clear); + } + + static void children_append(QQmlListProperty<QObject> *prop, QObject *o) + { + QObjectContainer *that = static_cast<QObjectContainer*>(prop->object); + that->dataChildren.append(o); + QObject::connect(o, SIGNAL(destroyed(QObject*)), prop->object, SLOT(childDestroyed(QObject*))); + QWidget *widget = qobject_cast<QWidget*>(o); + if (widget && that->widgetParent) + widget->setParent(that->widgetParent); + + if (that->gcOnAppend) { + QQmlEngine *engine = qmlEngine(that); + gc(*engine); + } + } + + static int children_count(QQmlListProperty<QObject> *prop) + { + return static_cast<QObjectContainer*>(prop->object)->dataChildren.count(); + } + + static QObject *children_at(QQmlListProperty<QObject> *prop, int index) + { + return static_cast<QObjectContainer*>(prop->object)->dataChildren.at(index); + } + + static void children_clear(QQmlListProperty<QObject> *prop) + { + QObjectContainer *that = static_cast<QObjectContainer*>(prop->object); + foreach (QObject *c, that->dataChildren) + QObject::disconnect(c, SIGNAL(destroyed(QObject*)), that, SLOT(childDestroyed(QObject*))); + that->dataChildren.clear(); + } + + QList<QObject*> dataChildren; + QWidget *widgetParent; + bool gcOnAppend; + +protected slots: + void childDestroyed(QObject *child) { + dataChildren.removeAll(child); + } +}; + +class QWidgetContainer : public QObjectContainer +{ + Q_OBJECT +public: + QWidgetContainer() + { + widgetParent = new QWidget; + QQmlEngine::setObjectOwnership(widgetParent, QQmlEngine::CppOwnership); + } + virtual ~QWidgetContainer() + { + delete widgetParent; + widgetParent = 0; + } +}; + +class QObjectContainerWithGCOnAppend : public QObjectContainer +{ + Q_OBJECT +public: + QObjectContainerWithGCOnAppend() + { + gcOnAppend = true; + } +}; + +tst_QWidgetsInQml::tst_QWidgetsInQml() +{ + qmlRegisterType<QWidget>("Qt.Widgets", 1, 0, "QWidget"); + qmlRegisterType<QObjectContainer>("Qt.Widgets", 1, 0, "QObjectContainer"); + qmlRegisterType<QWidgetContainer>("Qt.Widgets", 1, 0, "QWidgetContainer"); + qmlRegisterType<QObjectContainerWithGCOnAppend>("Qt.Widgets", 1, 0, "QObjectContainerWithGCOnAppend"); +} + +void tst_QWidgetsInQml::instantiateWidget() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import Qt.Widgets 1.0;\nQWidget { property QWidget child: QWidget { objectName: 'child' } }", QUrl()); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + QWidget *rootWidget = qobject_cast<QWidget*>(object.data()); + QVERIFY(rootWidget != 0); + QCOMPARE(rootWidget->children().count(), 1); + QWidget *firstChildWidget = qobject_cast<QWidget*>(rootWidget->children().first()); + QVERIFY(firstChildWidget != 0); + + QWidget *widgetProperty = qvariant_cast<QWidget*>(object->property("child")); + QVERIFY(widgetProperty != 0); + QCOMPARE(firstChildWidget, widgetProperty); + QCOMPARE(firstChildWidget->objectName(), QString("child")); +} + +void tst_QWidgetsInQml::instantiateWidgetWithoutParentWidget() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import Qt.Widgets 1.0;\n" + "import QtQml 2.0;\n" + "QtObject { property QtObject child: QWidget { objectName: 'child' } }", QUrl()); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QPointer<QWidget> widgetProperty = qvariant_cast<QWidget*>(object->property("child")); + QVERIFY(!widgetProperty.isNull()); + QCOMPARE(widgetProperty->objectName(), QString("child")); + + QVERIFY(!widgetProperty->parent()); + gc(engine); + // Don't collect, the property reference should keep it alive + QVERIFY(!widgetProperty.isNull()); +} + +void tst_QWidgetsInQml::widgetAsDefaultPropertyCollected() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import Qt.Widgets 1.0;\n" + "import QtQml 2.0;\n" + "QObjectContainer {\n" + " QWidget {\n" + " id: parentLessChild;\n" + " objectName: 'child'\n" + " }\n" + " property var widgetHolder;\n" + " Component.onCompleted: {\n" + " widgetHolder = parentLessChild;\n" + " }\n" + "}", QUrl()); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QObjectContainer *container = qobject_cast<QObjectContainer*>(object.data()); + QCOMPARE(container->dataChildren.count(), 1); + + QJSValue holder = qvariant_cast<QJSValue>(object->property("widgetHolder")); + QVERIFY(!holder.isNull()); + gc(engine); + QCOMPARE(container->dataChildren.count(), 1); + + holder = QJSValue(); + object->setProperty("widgetHolder", QVariant::fromValue(holder)); + + gc(engine); + // The QWidget is without a parent and nobody is referencing it anymore (the children + // list in QObjectContainer is weak!), so it should get collected. + QCOMPARE(container->dataChildren.count(), 0); +} + +void tst_QWidgetsInQml::widgetAsDefaultPropertyKept() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import Qt.Widgets 1.0;\n" + "import QtQml 2.0;\n" + "QWidgetContainer {\n" + " QWidget {\n" + " id: parentLessChild;\n" + " objectName: 'child'\n" + " }\n" + " property var widgetHolder;\n" + " Component.onCompleted: {\n" + " widgetHolder = parentLessChild;\n" + " }\n" + "}", QUrl()); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QWidgetContainer *container = qobject_cast<QWidgetContainer*>(object.data()); + QCOMPARE(container->dataChildren.count(), 1); + + QJSValue holder = qvariant_cast<QJSValue>(object->property("widgetHolder")); + QVERIFY(!holder.isNull()); + gc(engine); + QCOMPARE(container->dataChildren.count(), 1); + + holder = QJSValue(); + object->setProperty("widgetHolder", QVariant::fromValue(holder)); + + gc(engine); + QCOMPARE(container->dataChildren.count(), 1); +} + +void tst_QWidgetsInQml::widgetAsDefaultPropertyKeptDuringCreation() +{ + QQmlEngine engine; + QQmlComponent component(&engine); + component.setData("import Qt.Widgets 1.0;\n" + "import QtQml 2.0;\n" + "QObjectContainerWithGCOnAppend {\n" + " QWidget {\n" + " id: parentLessChild;\n" + " objectName: 'child'\n" + " property var blah;\n" // Ensures that we have a JS wrapper + " }\n" + "}", QUrl()); + QScopedPointer<QObject> object(component.create()); + QVERIFY(!object.isNull()); + + QObjectContainer *container = qobject_cast<QObjectContainer*>(object.data()); + QCOMPARE(container->dataChildren.count(), 1); + + gc(engine); + QCOMPARE(container->dataChildren.count(), 0); + +} + +QTEST_MAIN(tst_QWidgetsInQml) + +#include "tst_qwidgetsinqml.moc" |