qtdeclarative/tests/auto/qml/debugger/qqmlenginedebugservice/tst_qqmlenginedebugservice.cpp

1414 lines
50 KiB
C++
Raw Normal View History

// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "debugutil_p.h"
#include <QtQuickTestUtils/private/qmlutils_p.h>
#include <private/qqmlbinding_p.h>
#include <private/qqmlboundsignal_p.h>
#include <private/qqmldebugservice_p.h>
#include <private/qqmlmetatype_p.h>
#include <private/qqmlproperty_p.h>
#include <private/qqmldebugconnection_p.h>
#include <private/qqmlenginedebugclient_p.h>
#include <QtTest/qtest.h>
#include <QtTest/qsignalspy.h>
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlcomponent.h>
#include <QtQml/qqmlexpression.h>
#include <QtQml/qqmlproperty.h>
#include <QtQml/qqmlincubator.h>
#include <QtQml/qqmlapplicationengine.h>
#include <QtQuick/qquickitem.h>
#include <QtNetwork/qhostaddress.h>
#include <QtCore/qtimer.h>
#include <QtCore/qdebug.h>
#include <QtCore/qthread.h>
#include <QtCore/qabstractitemmodel.h>
#include <QtCore/qjsonobject.h>
#include <QtCore/qjsonarray.h>
#include <QtCore/qjsondocument.h>
#define QVERIFYOBJECT(statement) \
do {\
if (!QTest::qVerify((statement), #statement, "", __FILE__, __LINE__)) {\
return QQmlEngineDebugObjectReference();\
}\
} while (0)
class NonScriptProperty : public QObject {
Q_OBJECT
Q_PROPERTY(int nonScriptProp READ nonScriptProp WRITE setNonScriptProp NOTIFY nonScriptPropChanged SCRIPTABLE false)
public:
int nonScriptProp() const { return 0; }
void setNonScriptProp(int) {}
signals:
void nonScriptPropChanged();
};
QML_DECLARE_TYPE(NonScriptProperty)
class CustomTypes : public QObject
{
Q_OBJECT
Q_PROPERTY(QModelIndex modelIndex READ modelIndex)
public:
CustomTypes(QObject *parent = nullptr) : QObject(parent) {}
QModelIndex modelIndex() { return QModelIndex(); }
};
class JsonTest : public QObject
{
Q_OBJECT
Q_PROPERTY(QJsonObject data READ data WRITE setData NOTIFY dataChanged)
public:
JsonTest(QObject *parent = nullptr) : QObject(parent)
{
m_data["foo"] = QJsonValue(12);
m_data["ttt"] = QJsonArray({4, 5, 4, 3, 2});
m_data["a"] = QJsonValue(QJsonValue::Null);
m_data["b"] = QJsonValue(QJsonValue::Undefined);
m_data["c"] = QJsonValue("fffff");
}
QJsonObject data() const { return m_data; }
signals:
void dataChanged(const QJsonObject &data);
public slots:
void setData(const QJsonObject &data)
{
if (data != m_data) {
m_data = data;
emit dataChanged(data);
}
}
private:
QJsonObject m_data;
};
class tst_QQmlEngineDebugService : public QQmlDataTest
{
Q_OBJECT
public:
tst_QQmlEngineDebugService()
: QQmlDataTest(QT_QMLTEST_DATADIR)
, m_conn(nullptr)
, m_engine(nullptr)
, m_dbg(nullptr)
, m_rootItem(nullptr)
{
qmlRegisterType<NonScriptProperty>("Test", 1, 0, "NonScriptPropertyElement");
qmlRegisterType<CustomTypes>("Backend", 1, 0, "CustomTypes");
qmlRegisterType<JsonTest>("JsonTest", 1, 0, "JsonTest");
QTest::ignoreMessage(QtDebugMsg, "QML Debugger: Waiting for connection on port 3768...");
}
private:
QQmlEngineDebugObjectReference findRootObject(int context = 0,
bool recursive = false);
QQmlEngineDebugPropertyReference findProperty(
const QList<QQmlEngineDebugPropertyReference> &props,
const QString &name) const;
void recursiveObjectTest(QObject *o,
const QQmlEngineDebugObjectReference &oref,
bool recursive) const;
void getContexts();
std::unique_ptr<QQmlDebugConnection> m_conn;
std::unique_ptr<QQmlEngine> m_engine;
std::unique_ptr<QQmlContext> m_context;
std::vector<std::unique_ptr<QObject>> m_components;
QQmlEngineDebugClient *m_dbg;
QQuickItem *m_rootItem;
private slots:
void initTestCase() override;
void watch_property();
void watch_object();
void watch_expression();
void watch_expression_data();
void watch_context();
void watch_file();
void debuggerCrashOnAttach();
void queryAvailableEngines();
void queryRootContexts();
void queryObject();
void queryObject_data();
void queryObjectsForLocation();
void queryObjectsForLocation_data();
void queryExpressionResult();
void queryExpressionResult_data();
void queryExpressionResultInRootContext();
void queryExpressionResultBC();
void queryExpressionResultBC_data();
void setBindingForObject();
void resetBindingForObject();
void setMethodBody();
void queryObjectTree();
void setBindingInStates();
void regression_QTCREATORBUG_7451();
void queryObjectWithNonStreamableTypes();
void jsonData();
void asynchronousCreate();
void invalidContexts();
void createObjectOnDestruction();
void fetchValueType();
};
QQmlEngineDebugObjectReference tst_QQmlEngineDebugService::findRootObject(
int context, bool recursive)
{
bool success = false;
m_dbg->queryAvailableEngines(&success);
QVERIFYOBJECT(success);
QVERIFYOBJECT(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QVERIFYOBJECT(m_dbg->engines().size());
m_dbg->queryRootContexts(m_dbg->engines()[0], &success);
QVERIFYOBJECT(success);
QVERIFYOBJECT(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QVERIFYOBJECT(m_dbg->rootContext().contexts.size());
QVERIFYOBJECT(m_dbg->rootContext().contexts.last().objects.size());
int count = m_dbg->rootContext().contexts.size();
recursive ? m_dbg->queryObjectRecursive(m_dbg->rootContext().contexts[count - context - 1].objects[0],
&success) :
m_dbg->queryObject(m_dbg->rootContext().contexts[count - context - 1].objects[0], &success);
QVERIFYOBJECT(success);
QVERIFYOBJECT(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
return m_dbg->object();
}
QQmlEngineDebugPropertyReference tst_QQmlEngineDebugService::findProperty(
const QList<QQmlEngineDebugPropertyReference> &props, const QString &name) const
{
for (const QQmlEngineDebugPropertyReference &p : props) {
if (p.name == name)
return p;
}
return QQmlEngineDebugPropertyReference();
}
void tst_QQmlEngineDebugService::recursiveObjectTest(
QObject *o, const QQmlEngineDebugObjectReference &oref, bool recursive) const
{
const QMetaObject *meta = o->metaObject();
QCOMPARE(oref.debugId, QQmlDebugService::idForObject(o));
QCOMPARE(oref.name, o->objectName());
QCOMPARE(oref.className, QQmlMetaType::prettyTypeName(o));
QCOMPARE(oref.contextDebugId, QQmlDebugService::idForObject(
qmlContext(o)));
const QObjectList &children = o->children();
for (int i=0; i<children.size(); i++) {
QObject *child = children[i];
if (!qmlContext(child))
continue;
int debugId = QQmlDebugService::idForObject(child);
QVERIFY(debugId >= 0);
QQmlEngineDebugObjectReference cref;
for (const QQmlEngineDebugObjectReference &ref : oref.children) {
QVERIFY(!ref.className.isEmpty());
if (ref.debugId == debugId) {
cref = ref;
break;
}
}
QVERIFY(cref.debugId >= 0);
if (recursive)
recursiveObjectTest(child, cref, true);
}
for (const QQmlEngineDebugPropertyReference &p : oref.properties) {
QCOMPARE(p.objectDebugId, QQmlDebugService::idForObject(o));
// signal properties are fake - they are generated from QQmlAbstractBoundSignal children
if (p.name.startsWith("on") && p.name.size() > 2 && p.name[2].isUpper()) {
QString signal = p.value.toString();
QQmlBoundSignalExpression *expr = QQmlPropertyPrivate::signalExpression(QQmlProperty(o, p.name));
QVERIFY(expr && expr->expression() == signal);
QVERIFY(p.valueTypeName.isEmpty());
QVERIFY(p.binding.isEmpty());
QVERIFY(!p.hasNotifySignal);
continue;
}
QMetaProperty pmeta = meta->property(meta->indexOfProperty(p.name.toUtf8().constData()));
QCOMPARE(p.name, QString::fromUtf8(pmeta.name()));
if (pmeta.userType() == QMetaType::QObjectStar) {
const QQmlEngineDebugObjectReference ref
= qvariant_cast<QQmlEngineDebugObjectReference>(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.userType() < QMetaType::User && pmeta.userType() != QMetaType::QVariant) {
const QVariant expected = pmeta.read(o);
QVariant value = p.value;
QMetaType expectedType = expected.metaType();
if (value != expected && p.value.canConvert(expectedType))
value.convert(expectedType);
QVERIFY2(value == expected, QString::fromLatin1("%1 != %2. Details: %3/%4/%5/%6")
.arg(p.value.toString(), expected.toString(), p.name, p.valueTypeName)
.arg(pmeta.userType()).arg(pmeta.userType()).toUtf8());
}
if (p.name == "parent")
QVERIFY(p.valueTypeName == "QGraphicsObject*" ||
p.valueTypeName == "QQuickItem*");
else
QCOMPARE(p.valueTypeName, QString::fromUtf8(pmeta.typeName()));
QQmlAbstractBinding *binding =
QQmlPropertyPrivate::binding(
QQmlProperty(o, p.name));
if (binding)
QCOMPARE(binding->expression(), p.binding);
QCOMPARE(p.hasNotifySignal, pmeta.hasNotifySignal());
QVERIFY(pmeta.isValid());
}
}
void tst_QQmlEngineDebugService::getContexts()
{
bool success = false;
m_dbg->queryAvailableEngines(&success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QList<QQmlEngineDebugEngineReference> engines = m_dbg->engines();
QCOMPARE(engines.size(), 1);
m_dbg->queryRootContexts(engines.first(), &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
}
void tst_QQmlEngineDebugService::initTestCase()
{
QQmlDataTest::initTestCase();
m_components.clear();
m_engine = std::make_unique<QQmlEngine>(this);
// The contents of these files was previously hardcoded as QList<QByteArray>
// directly in this test, but that fails on Android, because the required
// dependencies are not deployed. When the contents is moved to separate
// files, qmlimportscanner is capable of providing all the necessary
// dependencies.
// Note that the order of the files in this list matters! The test-cases
// expect Qml components to be created is certain order.
constexpr const char *fileNames[] = {
"complexItem.qml",
"emptyItem.qml",
"itemWithFunctions.qml",
"rectangleWithTransitions.qml",
"customTypes.qml",
"jsonTest.qml",
"debuggerCrashOnAttach.qml"
};
for (auto file : fileNames) {
QQmlComponent component(m_engine.get(), testFileUrl(file));
QVERIFY(component.isReady()); // fails if bad syntax
m_components.push_back(std::unique_ptr<QObject>(component.create()));
}
m_rootItem = qobject_cast<QQuickItem*>(m_components.at(0).get());
// add an extra context to test for multiple contexts
m_context = std::make_unique<QQmlContext>(m_engine->rootContext(), this);
m_context->setObjectName("tst_QQmlDebug_childContext");
m_conn = std::make_unique<QQmlDebugConnection>(this);
m_conn->connectToHost("127.0.0.1", 3768);
bool ok = m_conn->waitForConnected();
QVERIFY(ok);
m_dbg = new QQmlEngineDebugClient(m_conn.get());
const QList<QQmlDebugClient *> others = QQmlDebugTest::createOtherClients(m_conn.get());
QTRY_COMPARE(m_dbg->state(), QQmlEngineDebugClient::Enabled);
for (QQmlDebugClient *other : others)
QCOMPARE(other->state(), QQmlDebugClient::Unavailable);
qDeleteAll(others);
}
void tst_QQmlEngineDebugService::setMethodBody()
{
bool success;
QQmlEngineDebugObjectReference obj = findRootObject(2);
QVERIFY(!obj.className.isEmpty());
QObject *root = m_components.at(2).get();
// Without args
{
QVariant rv;
QVERIFY(QMetaObject::invokeMethod(root, "myMethodNoArgs", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, rv)));
QCOMPARE(rv, QVariant(qreal(3)));
QVERIFY(m_dbg->setMethodBody(obj.debugId, "myMethodNoArgs", "return 7",
&success));
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QVERIFY(QMetaObject::invokeMethod(root, "myMethodNoArgs", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, rv)));
QCOMPARE(rv, QVariant(qreal(7)));
}
// With args
{
QVariant rv;
QVERIFY(QMetaObject::invokeMethod(root, "myMethod", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, rv), Q_ARG(QVariant, QVariant(19))));
QCOMPARE(rv, QVariant(qreal(28)));
QVERIFY(m_dbg->setMethodBody(obj.debugId, "myMethod", "return a + 7",
&success));
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QVERIFY(QMetaObject::invokeMethod(root, "myMethod", Qt::DirectConnection,
Q_RETURN_ARG(QVariant, rv), Q_ARG(QVariant, QVariant(19))));
QCOMPARE(rv, QVariant(qreal(26)));
}
}
void tst_QQmlEngineDebugService::watch_property()
{
QQmlEngineDebugObjectReference obj = findRootObject();
QVERIFY(!obj.className.isEmpty());
QQmlEngineDebugPropertyReference prop = findProperty(obj.properties, "width");
bool success;
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->addWatch(prop, &success);
QVERIFY(!success);
delete unconnected;
m_dbg->addWatch(QQmlEngineDebugPropertyReference(), &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), false);
quint32 id = m_dbg->addWatch(prop, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
QSignalSpy spy(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant)));
int origWidth = m_rootItem->property("width").toInt();
m_rootItem->setProperty("width", origWidth*2);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant))));
QCOMPARE(spy.size(), 1);
m_dbg->removeWatch(id, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
// restore original value and verify spy doesn't get additional signal since watch has been removed
m_rootItem->setProperty("width", origWidth);
QTest::qWait(100);
QCOMPARE(spy.size(), 1);
QCOMPARE(spy.at(0).at(0).value<QByteArray>(), prop.name.toUtf8());
Fix deprecation warnings about QVariant API Fix warnings like: sruntime/qv4serialize.cpp:378:45: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlListModelWorkerAgent::VariantRef]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qml/qqmlvmemetaobject.cpp:597:61: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1319:66: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1350:60: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8396:78: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8693:80: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:126:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:127:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:713:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:714:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qquickcustomparticle.cpp:416:89: warning: 'QVariant qVariantFromValue(const T&) [with T = double]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qqmlenginedebugclient.cpp:403:47: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlEngineDebugObjectReference]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] Task-number: QTBUG-74043 Change-Id: I14cb7d7c1fb8dc6321e32208a7de15f6bdb19065 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2019-04-05 07:42:17 +00:00
QCOMPARE(spy.at(0).at(1).value<QVariant>(), QVariant::fromValue(origWidth*2));
}
void tst_QQmlEngineDebugService::watch_object()
{
QQmlEngineDebugObjectReference obj = findRootObject();
QVERIFY(!obj.className.isEmpty());
bool success;
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->addWatch(obj, &success);
QVERIFY(!success);
delete unconnected;
m_dbg->addWatch(QQmlEngineDebugObjectReference(), &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), false);
quint32 id = m_dbg->addWatch(obj, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
QSignalSpy spy(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant)));
int origWidth = m_rootItem->property("width").toInt();
int origHeight = m_rootItem->property("height").toInt();
m_rootItem->setProperty("width", origWidth*2);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant))));
m_rootItem->setProperty("height", origHeight*2);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant))));
QVERIFY(spy.size() > 0);
int newWidth = -1;
int newHeight = -1;
for (int i=0; i<spy.size(); i++) {
const QVariantList &values = spy[i];
if (values[0].value<QByteArray>() == "width")
newWidth = values[1].value<QVariant>().toInt();
else if (values[0].value<QByteArray>() == "height")
newHeight = values[1].value<QVariant>().toInt();
}
m_dbg->removeWatch(id, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
// since watch has been removed, restoring the original values should not trigger a valueChanged()
spy.clear();
m_rootItem->setProperty("width", origWidth);
m_rootItem->setProperty("height", origHeight);
QTest::qWait(100);
QCOMPARE(spy.size(), 0);
QCOMPARE(newWidth, origWidth * 2);
QCOMPARE(newHeight, origHeight * 2);
}
void tst_QQmlEngineDebugService::watch_expression()
{
QFETCH(QString, expr);
QFETCH(int, increment);
QFETCH(int, incrementCount);
int origWidth = m_rootItem->property("width").toInt();
QQmlEngineDebugObjectReference obj = findRootObject();
QVERIFY(!obj.className.isEmpty());
bool success;
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->addWatch(obj, expr, &success);
QVERIFY(!success);
delete unconnected;
m_dbg->addWatch(QQmlEngineDebugObjectReference(), expr, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), false);
quint32 id = m_dbg->addWatch(obj, expr, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
QSignalSpy spy(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant)));
int width = origWidth;
for (int i=0; i<incrementCount+1; i++) {
if (i > 0) {
width += increment;
m_rootItem->setProperty("width", width);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(valueChanged(QByteArray,QVariant))));
}
}
m_dbg->removeWatch(id, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
// restore original value and verify spy doesn't get a signal since watch has been removed
m_rootItem->setProperty("width", origWidth);
QTest::qWait(100);
QCOMPARE(spy.size(), incrementCount);
width = origWidth + increment;
for (int i=0; i<spy.size(); i++) {
width += increment;
QCOMPARE(spy.at(i).at(1).value<QVariant>().toInt(), width);
}
}
void tst_QQmlEngineDebugService::watch_expression_data()
{
QTest::addColumn<QString>("expr");
QTest::addColumn<int>("increment");
QTest::addColumn<int>("incrementCount");
QTest::newRow("width") << "width" << 0 << 0;
QTest::newRow("width+10") << "width + 10" << 10 << 5;
}
void tst_QQmlEngineDebugService::watch_context()
{
QQmlEngineDebugContextReference c;
QTest::ignoreMessage(QtWarningMsg, "QQmlEngineDebugClient::addWatch(): Not implemented");
bool success;
m_dbg->addWatch(c, QString(), &success);
QVERIFY(!success);
}
void tst_QQmlEngineDebugService::watch_file()
{
QQmlEngineDebugFileReference f;
QTest::ignoreMessage(QtWarningMsg, "QQmlEngineDebugClient::addWatch(): Not implemented");
bool success;
m_dbg->addWatch(f, &success);
QVERIFY(!success);
}
void tst_QQmlEngineDebugService::queryAvailableEngines()
{
bool success;
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->queryAvailableEngines(&success);
QVERIFY(!success);
delete unconnected;
m_dbg->queryAvailableEngines(&success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
// TODO test multiple engines
const QList<QQmlEngineDebugEngineReference> engines = m_dbg->engines();
QCOMPARE(engines.size(), 1);
for (const QQmlEngineDebugEngineReference &e : engines) {
QCOMPARE(e.debugId, QQmlDebugService::idForObject(m_engine.get()));
QCOMPARE(e.name, m_engine->objectName());
}
}
void tst_QQmlEngineDebugService::queryRootContexts()
{
bool success;
m_dbg->queryAvailableEngines(&success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QVERIFY(m_dbg->engines().size());
const QQmlEngineDebugEngineReference engine = m_dbg->engines()[0];
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->queryRootContexts(engine, &success);
QVERIFY(!success);
delete unconnected;
m_dbg->queryRootContexts(engine, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QQmlContext *actualContext = m_engine->rootContext();
QQmlEngineDebugContextReference context = m_dbg->rootContext();
QCOMPARE(context.debugId, QQmlDebugService::idForObject(actualContext));
QCOMPARE(context.name, actualContext->objectName());
// root context query sends only root object data - it doesn't fill in
// the children or property info
QCOMPARE(context.objects.size(), 0);
QCOMPARE(context.contexts.size(), 8);
QVERIFY(context.contexts[0].debugId >= 0);
QCOMPARE(context.contexts[0].name, QString("tst_QQmlDebug_childContext"));
}
void tst_QQmlEngineDebugService::queryObject()
{
QFETCH(bool, recursive);
bool success;
QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
recursive ? unconnected->queryObjectRecursive(rootObject, &success) : unconnected->queryObject(rootObject, &success);
QVERIFY(!success);
delete unconnected;
recursive ? m_dbg->queryObjectRecursive(rootObject, &success) : m_dbg->queryObject(rootObject, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
const QQmlEngineDebugObjectReference obj = m_dbg->object();
QVERIFY(!obj.className.isEmpty());
// check source as defined in main()
QQmlEngineDebugFileReference source = obj.source;
QCOMPARE(source.url, testFileUrl("complexItem.qml"));
QCOMPARE(source.lineNumber, 6); // because of license header
QCOMPARE(source.columnNumber, 1);
// generically test all properties, children and childrens' properties
recursiveObjectTest(m_rootItem, obj, recursive);
if (recursive) {
for (const QQmlEngineDebugObjectReference &child : obj.children) {
QVERIFY(!child.className.isEmpty());
QVERIFY(child.properties.size() > 0);
}
QQmlEngineDebugObjectReference rect;
QQmlEngineDebugObjectReference text;
for (const QQmlEngineDebugObjectReference &child : obj.children) {
QVERIFY(!child.className.isEmpty());
if (child.className == "Rectangle")
rect = child;
else if (child.className == "Text")
text = child;
}
// test specific property values
Fix deprecation warnings about QVariant API Fix warnings like: sruntime/qv4serialize.cpp:378:45: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlListModelWorkerAgent::VariantRef]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qml/qqmlvmemetaobject.cpp:597:61: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1319:66: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1350:60: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8396:78: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8693:80: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:126:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:127:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:713:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:714:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qquickcustomparticle.cpp:416:89: warning: 'QVariant qVariantFromValue(const T&) [with T = double]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qqmlenginedebugclient.cpp:403:47: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlEngineDebugObjectReference]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] Task-number: QTBUG-74043 Change-Id: I14cb7d7c1fb8dc6321e32208a7de15f6bdb19065 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2019-04-05 07:42:17 +00:00
QCOMPARE(findProperty(rect.properties, "width").value, QVariant::fromValue(500));
QCOMPARE(findProperty(rect.properties, "height").value, QVariant::fromValue(600));
QVariant expected = findProperty(rect.properties, "color").value;
expected.convert(QMetaType::fromType<QColor>());
QCOMPARE(expected , QVariant::fromValue(QColor("blue")));
} else {
for (const QQmlEngineDebugObjectReference &child : obj.children) {
QVERIFY(!child.className.isEmpty());
QCOMPARE(child.properties.size(), 0);
}
}
}
void tst_QQmlEngineDebugService::queryObject_data()
{
QTest::addColumn<bool>("recursive");
QTest::newRow("non-recursive") << false;
QTest::newRow("recursive") << true;
}
void tst_QQmlEngineDebugService::queryObjectsForLocation()
{
QFETCH(bool, recursive);
bool success;
QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
const QString fileName = QFileInfo(rootObject.source.url.toString()).fileName();
int lineNumber = rootObject.source.lineNumber;
int columnNumber = rootObject.source.columnNumber;
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
recursive ? unconnected->queryObjectsForLocationRecursive(fileName, lineNumber,
columnNumber, &success)
: unconnected->queryObjectsForLocation(fileName, lineNumber,
columnNumber, &success);
QVERIFY(!success);
delete unconnected;
recursive ? m_dbg->queryObjectsForLocationRecursive(fileName, lineNumber,
columnNumber, &success)
: m_dbg->queryObjectsForLocation(fileName, lineNumber,
columnNumber, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->objects().size(), 1);
const QQmlEngineDebugObjectReference obj = m_dbg->objects().first();
QVERIFY(!obj.className.isEmpty());
// check source as defined in main()
QQmlEngineDebugFileReference source = obj.source;
QCOMPARE(source.url, testFileUrl(fileName));
QCOMPARE(source.lineNumber, lineNumber);
QCOMPARE(source.columnNumber, columnNumber);
// generically test all properties, children and childrens' properties
recursiveObjectTest(m_rootItem, obj, recursive);
if (recursive) {
for (const QQmlEngineDebugObjectReference &child : obj.children) {
QVERIFY(!child.className.isEmpty());
QVERIFY(child.properties.size() > 0);
}
QQmlEngineDebugObjectReference rect;
QQmlEngineDebugObjectReference text;
for (const QQmlEngineDebugObjectReference &child : obj.children) {
QVERIFY(!child.className.isEmpty());
if (child.className == "Rectangle")
rect = child;
else if (child.className == "Text")
text = child;
}
// test specific property values
Fix deprecation warnings about QVariant API Fix warnings like: sruntime/qv4serialize.cpp:378:45: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlListModelWorkerAgent::VariantRef]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qml/qqmlvmemetaobject.cpp:597:61: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1319:66: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1350:60: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8396:78: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8693:80: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:126:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:127:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:713:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:714:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qquickcustomparticle.cpp:416:89: warning: 'QVariant qVariantFromValue(const T&) [with T = double]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qqmlenginedebugclient.cpp:403:47: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlEngineDebugObjectReference]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] Task-number: QTBUG-74043 Change-Id: I14cb7d7c1fb8dc6321e32208a7de15f6bdb19065 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2019-04-05 07:42:17 +00:00
QCOMPARE(findProperty(rect.properties, "width").value, QVariant::fromValue(500));
QCOMPARE(findProperty(rect.properties, "height").value, QVariant::fromValue(600));
QVariant expected = findProperty(rect.properties, "color").value;
QMetaType colorMetatype = QMetaType::fromType<QColor>();
QVERIFY(expected.canConvert(colorMetatype));
expected.convert(colorMetatype);
QCOMPARE(expected , QVariant::fromValue(QColor("blue")));
} else {
for (const QQmlEngineDebugObjectReference &child : obj.children) {
QVERIFY(!child.className.isEmpty());
QCOMPARE(child.properties.size(), 0);
}
}
}
void tst_QQmlEngineDebugService::queryObjectsForLocation_data()
{
QTest::addColumn<bool>("recursive");
QTest::newRow("non-recursive") << false;
QTest::newRow("recursive") << true;
}
void tst_QQmlEngineDebugService::regression_QTCREATORBUG_7451()
{
const QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
int contextId = rootObject.contextDebugId;
QQmlContext *context = qobject_cast<QQmlContext *>(QQmlDebugService::objectForId(contextId));
QQmlComponent component(context->engine());
QByteArray content;
content.append("import QtQuick 2.0\n"
"Text {"
"y: 10\n"
"text: \"test\"\n"
"}");
component.setData(content, rootObject.source.url);
QObject *object = component.create(context);
QVERIFY(object);
int idNew = QQmlDebugService::idForObject(object);
QVERIFY(idNew >= 0);
const QString fileName = QFileInfo(rootObject.source.url.toString()).fileName();
int lineNumber = rootObject.source.lineNumber;
int columnNumber = rootObject.source.columnNumber;
bool success = false;
m_dbg->queryObjectsForLocation(fileName, lineNumber,
columnNumber, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
for (const QQmlEngineDebugObjectReference &child : rootObject.children) {
QVERIFY(!child.className.isEmpty());
success = false;
lineNumber = child.source.lineNumber;
columnNumber = child.source.columnNumber;
m_dbg->queryObjectsForLocation(fileName, lineNumber,
columnNumber, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
}
delete object;
QObject *deleted = QQmlDebugService::objectForId(idNew);
QVERIFY(!deleted);
lineNumber = rootObject.source.lineNumber;
columnNumber = rootObject.source.columnNumber;
success = false;
m_dbg->queryObjectsForLocation(fileName, lineNumber,
columnNumber, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
for (const QQmlEngineDebugObjectReference &child : rootObject.children) {
QVERIFY(!child.className.isEmpty());
success = false;
lineNumber = child.source.lineNumber;
columnNumber = child.source.columnNumber;
m_dbg->queryObjectsForLocation(fileName, lineNumber,
columnNumber, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
}
}
void tst_QQmlEngineDebugService::queryObjectWithNonStreamableTypes()
{
bool success;
QQmlEngineDebugObjectReference rootObject = findRootObject(4, true);
QVERIFY(!rootObject.className.isEmpty());
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->queryObject(rootObject, &success);
QVERIFY(!success);
delete unconnected;
m_dbg->queryObject(rootObject, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QQmlEngineDebugObjectReference obj = m_dbg->object();
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties, "modelIndex").value,
QVariant(QLatin1String("QModelIndex()")));
}
void tst_QQmlEngineDebugService::jsonData()
{
bool success;
QQmlEngineDebugObjectReference rootObject = findRootObject(5, true);
QVERIFY(!rootObject.className.isEmpty());
m_dbg->queryObject(rootObject, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QQmlEngineDebugObjectReference obj = m_dbg->object();
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties, "data").value,
QJsonDocument::fromJson("{\"a\":null,\"c\":\"fffff\",\"foo\":12,\"ttt\":[4,5,4,3,2]}")
.toVariant());
}
void tst_QQmlEngineDebugService::queryExpressionResult()
{
QFETCH(QString, expr);
QFETCH(QVariant, result);
int objectId = findRootObject().debugId;
bool success;
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->queryExpressionResult(objectId, expr, &success);
QVERIFY(!success);
delete unconnected;
m_dbg->queryExpressionResult(objectId, expr, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->resultExpr(), result);
}
void tst_QQmlEngineDebugService::queryExpressionResult_data()
{
QTest::addColumn<QString>("expr");
QTest::addColumn<QVariant>("result");
Fix deprecation warnings about QVariant API Fix warnings like: sruntime/qv4serialize.cpp:378:45: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlListModelWorkerAgent::VariantRef]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qml/qqmlvmemetaobject.cpp:597:61: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1319:66: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1350:60: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8396:78: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8693:80: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:126:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:127:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:713:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:714:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qquickcustomparticle.cpp:416:89: warning: 'QVariant qVariantFromValue(const T&) [with T = double]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qqmlenginedebugclient.cpp:403:47: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlEngineDebugObjectReference]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] Task-number: QTBUG-74043 Change-Id: I14cb7d7c1fb8dc6321e32208a7de15f6bdb19065 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2019-04-05 07:42:17 +00:00
QTest::newRow("width + 50") << "width + 50" << QVariant::fromValue(60);
QTest::newRow("blueRect.width") << "blueRect.width" << QVariant::fromValue(500);
QTest::newRow("bad expr") << "aeaef" << QVariant::fromValue(QString("<undefined>"));
QTest::newRow("QObject*") << "varObj" << QVariant::fromValue(QString("<unnamed object>"));
QTest::newRow("list of QObject*") << "varObjList" << QVariant::fromValue(QVariantList() << QVariant(QString("<unnamed object>")));
QVariantMap map;
map.insert(QLatin1String("rect"), QVariant(QLatin1String("<unnamed object>")));
Fix deprecation warnings about QVariant API Fix warnings like: sruntime/qv4serialize.cpp:378:45: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlListModelWorkerAgent::VariantRef]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qml/qqmlvmemetaobject.cpp:597:61: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1319:66: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1350:60: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8396:78: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8693:80: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:126:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:127:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:713:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:714:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qquickcustomparticle.cpp:416:89: warning: 'QVariant qVariantFromValue(const T&) [with T = double]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qqmlenginedebugclient.cpp:403:47: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlEngineDebugObjectReference]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] Task-number: QTBUG-74043 Change-Id: I14cb7d7c1fb8dc6321e32208a7de15f6bdb19065 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2019-04-05 07:42:17 +00:00
QTest::newRow("varObjMap") << "varObjMap" << QVariant::fromValue(map);
QTest::newRow("simpleVar") << "simpleVar" << QVariant::fromValue(10.05);
}
void tst_QQmlEngineDebugService::queryExpressionResultInRootContext()
{
bool success = false;
m_dbg->queryAvailableEngines(&success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QVERIFY(m_dbg->engines().size());
const QString exp = QLatin1String("1");
m_dbg->queryExpressionResult(-1, exp, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->resultExpr().toString(), exp);
}
void tst_QQmlEngineDebugService::queryExpressionResultBC()
{
QFETCH(QString, expr);
QFETCH(QVariant, result);
int objectId = findRootObject().debugId;
bool success;
QQmlEngineDebugClient *unconnected = new QQmlEngineDebugClient(nullptr);
unconnected->queryExpressionResultBC(objectId, expr, &success);
QVERIFY(!success);
delete unconnected;
m_dbg->queryExpressionResultBC(objectId, expr, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->resultExpr(), result);
}
void tst_QQmlEngineDebugService::queryExpressionResultBC_data()
{
QTest::addColumn<QString>("expr");
QTest::addColumn<QVariant>("result");
Fix deprecation warnings about QVariant API Fix warnings like: sruntime/qv4serialize.cpp:378:45: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlListModelWorkerAgent::VariantRef]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qml/qqmlvmemetaobject.cpp:597:61: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1319:66: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1350:60: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8396:78: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8693:80: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:126:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:127:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:713:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:714:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qquickcustomparticle.cpp:416:89: warning: 'QVariant qVariantFromValue(const T&) [with T = double]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qqmlenginedebugclient.cpp:403:47: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlEngineDebugObjectReference]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] Task-number: QTBUG-74043 Change-Id: I14cb7d7c1fb8dc6321e32208a7de15f6bdb19065 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2019-04-05 07:42:17 +00:00
QTest::newRow("width + 50") << "width + 50" << QVariant::fromValue(60);
QTest::newRow("blueRect.width") << "blueRect.width" << QVariant::fromValue(500);
QTest::newRow("bad expr") << "aeaef" << QVariant::fromValue(QString("<undefined>"));
QTest::newRow("QObject*") << "varObj" << QVariant::fromValue(QString("<unnamed object>"));
QTest::newRow("list of QObject*") << "varObjList" << QVariant::fromValue(QVariantList() << QVariant(QString("<unnamed object>")));
QVariantMap map;
map.insert(QLatin1String("rect"), QVariant(QLatin1String("<unnamed object>")));
Fix deprecation warnings about QVariant API Fix warnings like: sruntime/qv4serialize.cpp:378:45: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlListModelWorkerAgent::VariantRef]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qml/qqmlvmemetaobject.cpp:597:61: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1319:66: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] jsruntime/qv4engine.cpp:1350:60: warning: 'QVariant qVariantFromValue(const T&) [with T = QList<QObject*>]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8396:78: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickitem.cpp:8693:80: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:126:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickgenericshadereffect.cpp:127:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:713:69: warning: 'QVariant qVariantFromValue(const T&) [with T = QObject*]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] items/qquickopenglshadereffect.cpp:714:55: warning: 'QVariant qVariantFromValue(const T&) [with T = QSize]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qquickcustomparticle.cpp:416:89: warning: 'QVariant qVariantFromValue(const T&) [with T = double]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] qqmlenginedebugclient.cpp:403:47: warning: 'QVariant qVariantFromValue(const T&) [with T = QQmlEngineDebugObjectReference]' is deprecated: Use QVariant::fromValue() instead. [-Wdeprecated-declarations] Task-number: QTBUG-74043 Change-Id: I14cb7d7c1fb8dc6321e32208a7de15f6bdb19065 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
2019-04-05 07:42:17 +00:00
QTest::newRow("varObjMap") << "varObjMap" << QVariant::fromValue(map);
QTest::newRow("simpleVar") << "simpleVar" << QVariant::fromValue(10.05);
}
void tst_QQmlEngineDebugService::setBindingForObject()
{
QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QVERIFY(rootObject.debugId != -1);
QQmlEngineDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(10));
QCOMPARE(widthPropertyRef.binding, QString());
bool success;
//
// set literal
//
m_dbg->setBindingForObject(rootObject.debugId, "width", "15", true,
QString(), -1, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(15));
QCOMPARE(widthPropertyRef.binding, QString());
//
// set expression
//
m_dbg->setBindingForObject(rootObject.debugId, "width", "height", false,
QString(), -1, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(20));
QEXPECT_FAIL("", "Cannot retrieve text for a binding (QTBUG-37273)", Continue);
QCOMPARE(widthPropertyRef.binding, QString("height"));
//
// set handler
//
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QCOMPARE(rootObject.children.size(), 5); // Rectangle, Text, MouseArea, Component.onCompleted, NonScriptPropertyElement
QQmlEngineDebugObjectReference mouseAreaObject = rootObject.children.at(2);
QVERIFY(!mouseAreaObject.className.isEmpty());
m_dbg->queryObjectRecursive(mouseAreaObject, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
mouseAreaObject = m_dbg->object();
QCOMPARE(mouseAreaObject.className, QString("MouseArea"));
QQmlEngineDebugPropertyReference onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
QCOMPARE(onEnteredRef.name, QString("onEntered"));
Compile binding expressions in the QQmlCompiler This is done by re-using the JS code generator from the new compiler. A few bugs were fixed on the way: * The index into the compiledData->runtimeFunctions array is not the same as the function index when they are collected (from the AST), as for example binding expressions may create extra V4IR::Function objects that break the 1:1 mapping. Therefore the JS code gen will return a mapping from incoming function index to V4IR::Module::Function (and thus runtimeFunction) * Binding expressions in the old backend get usually unpacked from their ExpressionStatement node. The reference to that node is lost, and instead of trying to preserve it, we simply synthesize it again. This won't be necessary anymore with the new compiler in the future. * Commit 1c29d63d6045cf9d58cbc0f850de8fa50bf75d09 ensured to always look up locals by name, and so we have to do the same when initializing the closures of nested functions inside binding expressions (in qv4codegen.cpp) * Had to change the Qml debugger service auto-test, which does toString() on a function that is now compiled. Even if we implemented FunctionPrototype::toString() to do what v8 does by extracting the string from the file, it wouldn't help in this test, because it feeds the input from a string instead of a file. * In tst_parserstress we now end up compiling all JS code, which previously was only parsed. This triggers some bugs in the SSA handling. Those tests are skipped and tracked in QTBUG-34047 Change-Id: I44df51085510da0fd3d99eb5f1c7d4d17bcffdcf Reviewed-by: Lars Knoll <lars.knoll@digia.com>
2013-10-08 09:44:57 +00:00
// Sorry, can't do that anymore: QCOMPARE(onEnteredRef.value, QVariant("{ console.log('hello') }"));
QCOMPARE(onEnteredRef.value, QVariant("function() { [native code] }"));
m_dbg->setBindingForObject(mouseAreaObject.debugId, "onEntered",
"{console.log('hello, world') }", false,
QString(), -1, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
mouseAreaObject = rootObject.children.at(2);
QVERIFY(!mouseAreaObject.className.isEmpty());
m_dbg->queryObjectRecursive(mouseAreaObject, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
mouseAreaObject = m_dbg->object();
QVERIFY(!mouseAreaObject.className.isEmpty());
onEnteredRef = findProperty(mouseAreaObject.properties, "onEntered");
QCOMPARE(onEnteredRef.name, QString("onEntered"));
QCOMPARE(onEnteredRef.value, QVariant("function() { [native code] }"));
}
void tst_QQmlEngineDebugService::resetBindingForObject()
{
QQmlEngineDebugObjectReference rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QVERIFY(rootObject.debugId != -1);
QQmlEngineDebugPropertyReference widthPropertyRef = findProperty(rootObject.properties, "width");
bool success = false;
m_dbg->setBindingForObject(rootObject.debugId, "width", "15", true,
QString(), -1, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
//
// reset
//
m_dbg->resetBindingForObject(rootObject.debugId, "width", &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
widthPropertyRef = findProperty(rootObject.properties, "width");
QCOMPARE(widthPropertyRef.value, QVariant(0));
QCOMPARE(widthPropertyRef.binding, QString());
//
// reset nested property
//
success = false;
m_dbg->resetBindingForObject(rootObject.debugId, "font.bold", &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
rootObject = findRootObject();
QVERIFY(!rootObject.className.isEmpty());
QQmlEngineDebugPropertyReference boldPropertyRef = findProperty(rootObject.properties, "font.bold");
QCOMPARE(boldPropertyRef.value.toBool(), false);
QCOMPARE(boldPropertyRef.binding, QString());
}
void tst_QQmlEngineDebugService::setBindingInStates()
{
// Check if changing bindings of propertychanges works
const int sourceIndex = 3;
QQmlEngineDebugObjectReference obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QVERIFY(obj.debugId != -1);
QVERIFY(obj.children.size() >= 2);
bool success;
// We are going to switch state a couple of times, we need to get rid of the transition before
m_dbg->queryExpressionResult(obj.debugId,QString("transitions = []"), &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
// check initial value of the property that is changing
m_dbg->queryExpressionResult(obj.debugId,QString("state=\"state1\""), &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),200);
m_dbg->queryExpressionResult(obj.debugId,QString("state=\"\""),
&success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex, true);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),100);
// change the binding
QQmlEngineDebugObjectReference state = obj.children[1];
QCOMPARE(state.className, QString("State"));
QVERIFY(state.children.size() > 0);
QQmlEngineDebugObjectReference propertyChange = state.children[0];
QVERIFY(!propertyChange.className.isEmpty());
QVERIFY(propertyChange.debugId != -1);
m_dbg->setBindingForObject(propertyChange.debugId, "width",QVariant(300),true,
QString(), -1, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
// check properties changed in state
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),100);
m_dbg->queryExpressionResult(obj.debugId,QString("state=\"state1\""), &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),300);
// check changing properties of base state from within a state
m_dbg->setBindingForObject(obj.debugId,"width","height*2",false,
QString(), -1, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
m_dbg->setBindingForObject(obj.debugId,"height","200",true,
QString(), -1, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(),300);
m_dbg->queryExpressionResult(obj.debugId,QString("state=\"\""), &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 400);
// reset binding while in a state
m_dbg->queryExpressionResult(obj.debugId,QString("state=\"state1\""), &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 300);
m_dbg->resetBindingForObject(propertyChange.debugId, "width", &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 400);
// re-add binding
m_dbg->setBindingForObject(propertyChange.debugId, "width", "300", true,
QString(), -1, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
obj = findRootObject(sourceIndex);
QVERIFY(!obj.className.isEmpty());
QCOMPARE(findProperty(obj.properties,"width").value.toInt(), 300);
}
void tst_QQmlEngineDebugService::queryObjectTree()
{
const int sourceIndex = 3;
QQmlEngineDebugObjectReference obj = findRootObject(sourceIndex, true);
QVERIFY(!obj.className.isEmpty());
QVERIFY(obj.debugId != -1);
QVERIFY(obj.children.size() >= 2);
// check state
QQmlEngineDebugObjectReference state = obj.children[1];
QCOMPARE(state.className, QString("State"));
QVERIFY(state.children.size() > 0);
QQmlEngineDebugObjectReference propertyChange = state.children[0];
QVERIFY(!propertyChange.className.isEmpty());
QVERIFY(propertyChange.debugId != -1);
QQmlEngineDebugPropertyReference propertyChangeTarget = findProperty(propertyChange.properties,"target");
QCOMPARE(propertyChangeTarget.objectDebugId, propertyChange.debugId);
QQmlEngineDebugObjectReference targetReference = qvariant_cast<QQmlEngineDebugObjectReference>(propertyChangeTarget.value);
QVERIFY(!targetReference.className.isEmpty());
QCOMPARE(targetReference.debugId, -1);
QCOMPARE(targetReference.name, QString("<unnamed object>"));
// check transition
QQmlEngineDebugObjectReference transition = obj.children[0];
QCOMPARE(transition.className, QString("Transition"));
QCOMPARE(findProperty(transition.properties,"from").value.toString(), QString("*"));
QCOMPARE(findProperty(transition.properties,"to").value, findProperty(state.properties,"name").value);
QVERIFY(transition.children.size() > 0);
QQmlEngineDebugObjectReference animation = transition.children[0];
QVERIFY(!animation.className.isEmpty());
QVERIFY(animation.debugId != -1);
QQmlEngineDebugPropertyReference animationTarget = findProperty(animation.properties,"target");
QCOMPARE(animationTarget.objectDebugId, animation.debugId);
targetReference = qvariant_cast<QQmlEngineDebugObjectReference>(animationTarget.value);
QVERIFY(!targetReference.className.isEmpty());
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);
}
void tst_QQmlEngineDebugService::asynchronousCreate() {
QQmlEngineDebugObjectReference object;
auto connection = connect(m_dbg, &QQmlEngineDebugClient::newObject, this, [&](int objectId) {
object.debugId = objectId;
});
QByteArray asynchronousComponent = "import QtQuick 2.5\n"
"Rectangle { id: asyncRect }";
QQmlComponent component(m_engine.get());
component.setData(asynchronousComponent, QUrl::fromLocalFile(""));
QVERIFY(component.isReady()); // fails if bad syntax
QQmlIncubator incubator(QQmlIncubator::Asynchronous);
const auto guard = qScopeGuard([&](){ delete incubator.object(); });
component.create(incubator);
QVERIFY(m_dbg->object().idString != QLatin1String("asyncRect"));
QTRY_VERIFY(object.debugId != -1);
disconnect(connection);
bool success = false;
m_dbg->queryObject(object, &success);
QVERIFY(success);
QTRY_COMPARE(m_dbg->object().idString, QLatin1String("asyncRect"));
}
void tst_QQmlEngineDebugService::invalidContexts()
{
getContexts();
const int base = m_dbg->rootContext().contexts.size();
QQmlContext context(m_engine.get());
getContexts();
QCOMPARE(m_dbg->rootContext().contexts.size(), base + 1);
QQmlRefPointer<QQmlContextData> contextData = QQmlContextData::get(&context);
contextData->invalidate();
getContexts();
QCOMPARE(m_dbg->rootContext().contexts.size(), base);
QQmlRefPointer<QQmlContextData> rootData = QQmlContextData::get(m_engine->rootContext());
const auto guard = qScopeGuard([this]() { initTestCase(); }); // Re-init to restore the contexts
rootData->invalidate();
getContexts();
QCOMPARE(m_dbg->rootContext().contexts.size(), 0);
}
void tst_QQmlEngineDebugService::createObjectOnDestruction()
{
QSignalSpy spy(m_dbg, SIGNAL(newObject(int)));
QScopedPointer<QObject> o;
{
QQmlEngine engine;
QQmlComponent component(&engine);
component.setData(
"import QtQml 2.0;"
"QtObject {"
"property Component x:"
"Qt.createQmlObject('import QtQml 2.0; Component { QtObject { } }',"
"this, 'x.qml');"
"Component.onDestruction: x.createObject(this, {});"
"}", QUrl::fromLocalFile("x.qml"));
QVERIFY(component.isReady());
o.reset(component.create());
QVERIFY(!o.isNull());
QTRY_COMPARE(spy.size(), 2);
}
// Doesn't crash and doesn't give us another signal for the object created on destruction.
QTest::qWait(500);
QCOMPARE(spy.size(), 2);
}
void tst_QQmlEngineDebugService::fetchValueType()
{
QQmlApplicationEngine engine;
engine.load(testFileUrl("fetchValueType.qml"));
bool success = false;
m_dbg->queryAvailableEngines(&success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QVERIFY(m_dbg->engines().size() > 1);
QQmlEngineDebugObjectReference object;
object.debugId = QQmlDebugService::idForObject(&engine);
m_dbg->queryObjectRecursive(object, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
}
void tst_QQmlEngineDebugService::debuggerCrashOnAttach() {
QQmlEngineDebugObjectReference obj = findRootObject(6);
QVERIFY(!obj.className.isEmpty());
bool success;
m_dbg->addWatch(obj, &success);
QVERIFY(success);
QVERIFY(QQmlDebugTest::waitForSignal(m_dbg, SIGNAL(result())));
QCOMPARE(m_dbg->valid(), true);
}
int main(int argc, char *argv[])
{
int _argc = argc + 1;
QScopedArrayPointer<char *>_argv(new char*[_argc]);
for (int i = 0; i < argc; ++i)
_argv[i] = argv[i];
char arg[] = "-qmljsdebugger=port:3768,services:QmlDebugger";
_argv[_argc - 1] = arg;
QGuiApplication app(_argc, _argv.data());
tst_QQmlEngineDebugService tc;
return QTest::qExec(&tc, _argc, _argv.data());
}
#include "tst_qqmlenginedebugservice.moc"