diff options
author | Milian Wolff <milian.wolff@kdab.com> | 2015-02-04 19:12:12 +0100 |
---|---|---|
committer | Milian Wolff <milian.wolff@kdab.com> | 2015-02-04 19:12:12 +0100 |
commit | 801076803ce92d7bd646a58c792015c2b833d0c5 (patch) | |
tree | b9bc16705a541cf402ee4614da7115135efb19d5 | |
parent | 9d705911391c456813ce54a52f70aa2ccbc5b553 (diff) | |
parent | 358e5acba3154a8ab4b53b22797c2c1eae4707dc (diff) | |
download | qtwebchannel-801076803ce92d7bd646a58c792015c2b833d0c5.tar.gz |
Merge branch '5.4' into dev
This merge required extensive conflict handling because
the bug fix in 5.4 to properly wrap and forward QObjects
referenced by published objects' properties clashed with
some feature additions in dev, namely the client separation
logic.
All unit test pass for me locally now again.
Conflicts:
.qmake.conf
src/webchannel/qmetaobjectpublisher.cpp
tests/auto/qml/tst_webchannel.qml
Change-Id: If3d00e13b265c6ab9fb2c38023014f97f8e7779b
-rw-r--r-- | src/imports/webchannel/plugins.qmltypes | 62 | ||||
-rw-r--r-- | src/imports/webchannel/webchannel.pro | 2 | ||||
-rw-r--r-- | src/webchannel/qmetaobjectpublisher.cpp | 112 | ||||
-rw-r--r-- | src/webchannel/qmetaobjectpublisher_p.h | 15 | ||||
-rw-r--r-- | src/webchannel/qwebchannel.js | 36 | ||||
-rw-r--r-- | src/webchannel/signalhandler_p.h | 25 | ||||
-rw-r--r-- | tests/auto/qml/tst_multiclient.qml | 21 | ||||
-rw-r--r-- | tests/auto/qml/tst_webchannel.qml | 17 | ||||
-rw-r--r-- | tests/auto/qml/tst_webchannelseparation.qml | 26 | ||||
-rw-r--r-- | tests/auto/webchannel/tst_webchannel.cpp | 32 | ||||
-rw-r--r-- | tests/auto/webchannel/tst_webchannel.h | 1 |
11 files changed, 230 insertions, 119 deletions
diff --git a/src/imports/webchannel/plugins.qmltypes b/src/imports/webchannel/plugins.qmltypes index 789f2b4..4d0155d 100644 --- a/src/imports/webchannel/plugins.qmltypes +++ b/src/imports/webchannel/plugins.qmltypes @@ -4,49 +4,21 @@ import QtQuick.tooling 1.1 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -notrelocatable QtWebChannel 1.0' +// 'qmlplugindump -nonrelocatable QtWebChannel 1.0' Module { Component { - name: "QWebChannel" - prototype: "QObject" - Property { name: "blockUpdates"; type: "bool" } - Signal { - name: "blockUpdatesChanged" - Parameter { name: "block"; type: "bool" } - } - Method { - name: "sendMessage" - Parameter { name: "id"; type: "QJsonValue" } - Parameter { name: "data"; type: "QJsonValue" } - } - Method { - name: "sendMessage" - Parameter { name: "id"; type: "QJsonValue" } - } - Method { - name: "registerObject" - Parameter { name: "id"; type: "string" } - Parameter { name: "object"; type: "QObject"; isPointer: true } - } - Method { - name: "deregisterObject" - Parameter { name: "object"; type: "QObject"; isPointer: true } - } - } - Component { - name: "QmlWebChannel" + name: "QQmlWebChannel" prototype: "QWebChannel" exports: ["QtWebChannel/WebChannel 1.0"] exportMetaObjectRevisions: [0] - attachedType: "QmlWebChannelAttached" + attachedType: "QQmlWebChannelAttached" Property { name: "transports"; type: "QObject"; isList: true; isReadonly: true } Property { name: "registeredObjects"; type: "QObject"; isList: true; isReadonly: true } Method { name: "registerObjects" Parameter { name: "objects"; type: "QVariantMap" } } - Method { name: "test_clientIsIdle"; type: "bool" } Method { name: "connectTo" Parameter { name: "transport"; type: "QObject"; isPointer: true } @@ -57,7 +29,7 @@ Module { } } Component { - name: "QmlWebChannelAttached" + name: "QQmlWebChannelAttached" prototype: "QObject" Property { name: "id"; type: "string" } Signal { @@ -65,4 +37,30 @@ Module { Parameter { name: "id"; type: "string" } } } + Component { + name: "QWebChannel" + prototype: "QObject" + Property { name: "blockUpdates"; type: "bool" } + Signal { + name: "blockUpdatesChanged" + Parameter { name: "block"; type: "bool" } + } + Method { + name: "connectTo" + Parameter { name: "transport"; type: "QWebChannelAbstractTransport"; isPointer: true } + } + Method { + name: "disconnectFrom" + Parameter { name: "transport"; type: "QWebChannelAbstractTransport"; isPointer: true } + } + Method { + name: "registerObject" + Parameter { name: "id"; type: "string" } + Parameter { name: "object"; type: "QObject"; isPointer: true } + } + Method { + name: "deregisterObject" + Parameter { name: "object"; type: "QObject"; isPointer: true } + } + } } diff --git a/src/imports/webchannel/webchannel.pro b/src/imports/webchannel/webchannel.pro index 8ae6ef5..4c8d322 100644 --- a/src/imports/webchannel/webchannel.pro +++ b/src/imports/webchannel/webchannel.pro @@ -3,6 +3,8 @@ QT = core quick webchannel-private INCLUDEPATH += ../../webchannel VPATH += ../../webchannel +IMPORT_VERSION = 1.0 + SOURCES += \ plugin.cpp diff --git a/src/webchannel/qmetaobjectpublisher.cpp b/src/webchannel/qmetaobjectpublisher.cpp index c476011..0c22798 100644 --- a/src/webchannel/qmetaobjectpublisher.cpp +++ b/src/webchannel/qmetaobjectpublisher.cpp @@ -104,15 +104,18 @@ QMetaObjectPublisher::~QMetaObjectPublisher() void QMetaObjectPublisher::registerObject(const QString &id, QObject *object) { - if (propertyUpdatesInitialized) { - qWarning("Registered new object after initialization. This does not work!"); - return; - } registeredObjects[id] = object; registeredObjectIds[object] = id; + if (propertyUpdatesInitialized) { + if (!webChannel->d_func()->transports.isEmpty()) { + qWarning("Registered new object after initialization, existing clients won't be notified!"); + // TODO: send a message to clients that an object was added + } + initializePropertyUpdates(object, classInfoForObject(object, Q_NULLPTR)); + } } -QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object) const +QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object, QWebChannelAbstractTransport *transport) { QJsonObject data; if (!object) { @@ -160,7 +163,7 @@ QJsonObject QMetaObjectPublisher::classInfoForObject(const QObject *object) cons prop.name(), object->metaObject()->className()); } propertyInfo.append(signalInfo); - propertyInfo.append(QJsonValue::fromVariant(prop.read(object))); + propertyInfo.append(wrapResult(prop.read(object), transport)); qtProperties.append(propertyInfo); } for (int i = 0; i < metaObject->methodCount(); ++i) { @@ -217,13 +220,13 @@ void QMetaObjectPublisher::setClientIsIdle(bool isIdle) } } -QJsonObject QMetaObjectPublisher::initializeClient() +QJsonObject QMetaObjectPublisher::initializeClient(QWebChannelAbstractTransport *transport) { QJsonObject objectInfos; { const QHash<QString, QObject *>::const_iterator end = registeredObjects.constEnd(); for (QHash<QString, QObject *>::const_iterator it = registeredObjects.constBegin(); it != end; ++it) { - const QJsonObject &info = classInfoForObject(it.value()); + const QJsonObject &info = classInfoForObject(it.value(), transport); if (!propertyUpdatesInitialized) { initializePropertyUpdates(it.value(), info); } @@ -280,6 +283,7 @@ void QMetaObjectPublisher::sendPendingPropertyUpdates() for (PendingPropertyUpdates::const_iterator it = pendingPropertyUpdates.constBegin(); it != end; ++it) { const QObject *object = it.key(); const QMetaObject *const metaObject = object->metaObject(); + const QString objectId = registeredObjectIds.value(object); const SignalToPropertyNameMap &objectsSignalToPropertyMap = signalToPropertyMap.value(object); // maps property name to current property value QJsonObject properties; @@ -291,12 +295,11 @@ void QMetaObjectPublisher::sendPendingPropertyUpdates() foreach (const int propertyIndex, objectsSignalToPropertyMap.value(sigIt.key())) { const QMetaProperty &property = metaObject->property(propertyIndex); Q_ASSERT(property.isValid()); - properties[QString::number(propertyIndex)] = QJsonValue::fromVariant(property.read(object)); + properties[QString::number(propertyIndex)] = wrapResult(property.read(object), Q_NULLPTR, objectId); } sigs[QString::number(sigIt.key())] = QJsonArray::fromVariantList(sigIt.value()); } QJsonObject obj; - const QString objectId = registeredObjectIds.value(object); obj[KEY_OBJECT] = objectId; obj[KEY_SIGNALS] = sigs; obj[KEY_PROPERTIES] = properties; @@ -400,9 +403,7 @@ void QMetaObjectPublisher::signalEmitted(const QObject *object, const int signal message[KEY_OBJECT] = objectName; message[KEY_SIGNAL] = signalIndex; if (!arguments.isEmpty()) { - // TODO: wrap (new) objects on the fly - QJsonArray args = QJsonArray::fromVariantList(arguments); - message[KEY_ARGS] = args; + message[KEY_ARGS] = wrapList(arguments, Q_NULLPTR, objectName); } message[KEY_TYPE] = TypeSignal; @@ -435,52 +436,77 @@ void QMetaObjectPublisher::objectDestroyed(const QObject *object) Q_ASSERT(removed); Q_UNUSED(removed); + signalHandler.remove(object); signalToPropertyMap.remove(object); pendingPropertyUpdates.remove(object); } -QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelAbstractTransport *transport) +// NOTE: transport can be a nullptr +// in such a case, we need to ensure that the property is registered to +// the target transports of the parentObjectId +QJsonValue QMetaObjectPublisher::wrapResult(const QVariant &result, QWebChannelAbstractTransport *transport, + const QString &parentObjectId) { if (QObject *object = result.value<QObject *>()) { QString id = registeredObjectIds.value(object); - - QJsonObject objectInfo; - - if (!id.isEmpty() && wrappedObjects.contains(id)) { - Q_ASSERT(object == wrappedObjects.value(id).object); - // check if this transport is already assigned to the object - if (!wrappedObjects.value(id).transports.contains(transport)) - wrappedObjects[id].transports.append(transport); - return wrappedObjects.value(id).classinfo; - } else { + QJsonObject classInfo; + if (id.isEmpty()) { + // neither registered, nor wrapped, do so now id = QUuid::createUuid().toString(); + Q_ASSERT(!registeredObjects.contains(id)); - QJsonObject info = classInfoForObject(object); - objectInfo[KEY_QOBJECT] = true; - objectInfo[KEY_ID] = id; - objectInfo[KEY_DATA] = info; + classInfo = classInfoForObject(object, transport); - if (!registeredObjects.contains(id)) { - registeredObjectIds[object] = id; - ObjectInfo oi(object, objectInfo); - oi.transports.append(transport); - wrappedObjects.insert(id, oi); + registeredObjectIds[object] = id; - initializePropertyUpdates(object, info); + ObjectInfo oi(object, classInfo); + if (transport) { + oi.transports.append(transport); + } else { + // use the transports from the parent object + oi.transports = wrappedObjects.value(parentObjectId).transports; + // or fallback to all transports if the parent is not wrapped + if (oi.transports.isEmpty()) + oi.transports = webChannel->d_func()->transports; } + wrappedObjects.insert(id, oi); + + initializePropertyUpdates(object, classInfo); + } else if (wrappedObjects.contains(id)) { + Q_ASSERT(object == wrappedObjects.value(id).object); + // check if this transport is already assigned to the object + if (transport && !wrappedObjects.value(id).transports.contains(transport)) + wrappedObjects[id].transports.append(transport); + classInfo = wrappedObjects.value(id).classinfo; } + + QJsonObject objectInfo; + objectInfo[KEY_QOBJECT] = true; + objectInfo[KEY_ID] = id; + if (!classInfo.isEmpty()) + objectInfo[KEY_DATA] = classInfo; return objectInfo; + } else if (result.canConvert<QJSValue>()) { + // Workaround for keeping QJSValues from QVariant. + // Calling QJSValue::toVariant() converts JS-objects/arrays to QVariantMap/List + // instead of stashing a QJSValue itself into a variant. + // TODO: Improve QJSValue-QJsonValue conversion in Qt. + return wrapResult(result.value<QJSValue>().toVariant(), transport, parentObjectId); + } else if (result.canConvert<QVariantList>()) { + // recurse and potentially wrap contents of the array + return wrapList(result.toList(), transport); } - // Workaround for keeping QJSValues from QVariant. - // Calling QJSValue::toVariant() converts JS-objects/arrays to QVariantMap/List - // instead of stashing a QJSValue itself into a variant. - // TODO: Improve QJSValue-QJsonValue conversion in Qt. - QVariant jsvVariant = result; - if (result.canConvert<QJSValue>()) - jsvVariant = result.value<QJSValue>().toVariant(); + return QJsonValue::fromVariant(result); +} - return QJsonValue::fromVariant(jsvVariant); +QJsonArray QMetaObjectPublisher::wrapList(const QVariantList &list, QWebChannelAbstractTransport *transport, const QString &parentObjectId) +{ + QJsonArray array; + foreach (const QVariant &arg, list) { + array.append(wrapResult(arg, transport, parentObjectId)); + } + return array; } void QMetaObjectPublisher::deleteWrappedObject(QObject *object) const @@ -525,7 +551,7 @@ void QMetaObjectPublisher::handleMessage(const QJsonObject &message, QWebChannel QJsonDocument(message).toJson().constData()); return; } - transport->sendMessage(createResponse(message.value(KEY_ID), initializeClient())); + transport->sendMessage(createResponse(message.value(KEY_ID), initializeClient(transport))); } else if (type == TypeDebug) { static QTextStream out(stdout); out << "DEBUG: " << message.value(KEY_DATA).toString() << endl; diff --git a/src/webchannel/qmetaobjectpublisher_p.h b/src/webchannel/qmetaobjectpublisher_p.h index 1d269f1..359135c 100644 --- a/src/webchannel/qmetaobjectpublisher_p.h +++ b/src/webchannel/qmetaobjectpublisher_p.h @@ -95,7 +95,7 @@ public: /** * Serialize the QMetaObject of @p object and return it in JSON form. */ - QJsonObject classInfoForObject(const QObject *object) const; + QJsonObject classInfoForObject(const QObject *object, QWebChannelAbstractTransport *transport); /** * Set the client to idle or busy, based on the value of @p isIdle. @@ -109,7 +109,7 @@ public: * * Furthermore, if that was not done already, connect to their property notify signals. */ - QJsonObject initializeClient(); + QJsonObject initializeClient(QWebChannelAbstractTransport *transport); /** * Go through all properties of the given object and connect to their notify signal. @@ -155,10 +155,17 @@ public: * return the objects class information. * * All other input types are returned as-is. + */ + QJsonValue wrapResult(const QVariant &result, QWebChannelAbstractTransport *transport, + const QString &parentObjectId = QString()); + + /** + * Convert a list of variant values for consumption by the client. * - * TODO: support wrapping of initially-registered objects + * This properly handles QML values and also wraps the result if required. */ - QJsonValue wrapResult(const QVariant &result, QWebChannelAbstractTransport *transport); + QJsonArray wrapList(const QVariantList &list, QWebChannelAbstractTransport *transport, + const QString &parentObjectId = QString()); /** * Invoke delete later on @p object. diff --git a/src/webchannel/qwebchannel.js b/src/webchannel/qwebchannel.js index 13e9da5..4a1c784 100644 --- a/src/webchannel/qwebchannel.js +++ b/src/webchannel/qwebchannel.js @@ -155,6 +155,10 @@ var QWebChannel = function(transport, initCallback) for (var objectName in data) { var object = new QObject(objectName, data[objectName], channel); } + // now unwrap properties, which might reference other registered objects + for (var objectName in channel.objects) { + channel.objects[objectName].unwrapProperties(); + } if (initCallback) { initCallback(channel); } @@ -177,18 +181,31 @@ function QObject(name, data, webChannel) // ---------------------------------------------------------------------- - function unwrapQObject( response ) + this.unwrapQObject = function(response) { + if (response instanceof Array) { + // support list of objects + var ret = new Array(response.length); + for (var i = 0; i < response.length; ++i) { + ret[i] = object.unwrapQObject(response[i]); + } + return ret; + } if (!response || !response["__QObject*__"] - || response["id"] === undefined - || response["data"] === undefined) { + || response["id"] === undefined) { return response; } + var objectId = response.id; if (webChannel.objects[objectId]) return webChannel.objects[objectId]; + if (!response.data) { + console.error("Cannot unwrap unknown QObject " + objectId + " without data."); + return; + } + var qObject = new QObject( objectId, response.data, webChannel ); qObject.destroyed.connect(function() { if (webChannel.objects[objectId] === qObject) { @@ -206,9 +223,18 @@ function QObject(name, data, webChannel) } } }); + // here we are already initialized, and thus must directly unwrap the properties + qObject.unwrapProperties(); return qObject; } + this.unwrapProperties = function() + { + for (var propertyIdx in object.__propertyCache__) { + object.__propertyCache__[propertyIdx] = object.unwrapQObject(object.__propertyCache__[propertyIdx]); + } + } + function addSignal(signalData, isPropertyNotifySignal) { var signalName = signalData[0]; @@ -311,7 +337,7 @@ function QObject(name, data, webChannel) "args": args }, function(response) { if (response !== undefined) { - var result = unwrapQObject(response); + var result = object.unwrapQObject(response); if (callback) { (callback)(result); } @@ -326,6 +352,8 @@ function QObject(name, data, webChannel) var propertyName = propertyInfo[1]; var notifySignalData = propertyInfo[2]; // initialize property cache with current value + // NOTE: if this is an object, it is not directly unwrapped as it might + // reference other QObject that we do not know yet object.__propertyCache__[propertyIndex] = propertyInfo[3]; if (notifySignalData) { diff --git a/src/webchannel/signalhandler_p.h b/src/webchannel/signalhandler_p.h index 2560cdb..03fbca9 100644 --- a/src/webchannel/signalhandler_p.h +++ b/src/webchannel/signalhandler_p.h @@ -84,6 +84,11 @@ public: */ void clear(); + /** + * Fully remove and disconnect an object from handler + */ + void remove(const QObject *object); + private: /** * Exctract the arguments of a signal call and pass them to the receiver. @@ -252,15 +257,6 @@ int SignalHandler<Receiver>::qt_metacall(QMetaObject::Call call, int methodId, v dispatch(object, methodId, args); - if (methodId == s_destroyedSignalIndex) { - // disconnect on QObject::destroyed - ConnectionHash::iterator it = m_connectionsCounter.find(object); - Q_ASSERT(it != m_connectionsCounter.end()); - foreach (const ConnectionPair &connection, *it) { - QObject::disconnect(connection.first); - } - m_connectionsCounter.erase(it); - } return -1; } return methodId; @@ -280,6 +276,17 @@ void SignalHandler<Receiver>::clear() m_signalArgumentTypes[&QObject::staticMetaObject] = keep; } +template<class Receiver> +void SignalHandler<Receiver>::remove(const QObject *object) +{ + Q_ASSERT(m_connectionsCounter.contains(object)); + const SignalConnectionHash &connections = m_connectionsCounter.value(object); + foreach (const ConnectionPair &connection, connections) { + QObject::disconnect(connection.first); + } + m_connectionsCounter.remove(object); +} + QT_END_NAMESPACE #endif // SIGNALHANDLER_H diff --git a/tests/auto/qml/tst_multiclient.qml b/tests/auto/qml/tst_multiclient.qml index 115857d..4977e50 100644 --- a/tests/auto/qml/tst_multiclient.qml +++ b/tests/auto/qml/tst_multiclient.qml @@ -87,14 +87,14 @@ TestCase { WebChannel.id: "myOtherObj" } + property var lastFactoryObj + property var createdFactoryObjects: [] QtObject { id: myFactory - property var lastObj - property var createdObjects: [] function cleanup() { - while (createdObjects.length) { - var obj = createdObjects.shift(); + while (createdFactoryObjects.length) { + var obj = createdFactoryObjects.shift(); if (obj) { obj.destroy(); } @@ -103,9 +103,9 @@ TestCase { function create(id) { - lastObj = component.createObject(myFactory, {objectName: id}); - createdObjects.push(lastObj); - return lastObj; + lastFactoryObj = component.createObject(myFactory, {objectName: id}); + createdFactoryObjects.push(lastFactoryObj); + return lastFactoryObj; } WebChannel.id: "myFactory" } @@ -139,7 +139,8 @@ TestCase { client2.debug = false; // delete all created objects myFactory.cleanup(); - myFactory.lastObj = undefined; + lastFactoryObj = undefined; + createdFactoryObjects = []; // reschedule current task to end of event loop wait(1); } @@ -180,7 +181,7 @@ TestCase { var channel1 = client1.createChannel(function (channel1) { channel1.objects.myFactory.create("testObj1", function (obj1) { - testObj1 = myFactory.lastObj; + testObj1 = lastFactoryObj; testObj1Id = obj1.__id__; // create second channel after factory has created first @@ -227,7 +228,7 @@ TestCase { channel2 = client2.createChannel(function (channel2) { channel2.objects.myFactory.create("testObj2", function (obj2) { - testObj2 = myFactory.lastObj; + testObj2 = lastFactoryObj; testObj2Id = obj2.__id__; }); }); diff --git a/tests/auto/qml/tst_webchannel.qml b/tests/auto/qml/tst_webchannel.qml index f41c4fa..3bfbfc9 100644 --- a/tests/auto/qml/tst_webchannel.qml +++ b/tests/auto/qml/tst_webchannel.qml @@ -67,6 +67,8 @@ TestCase { WebChannel.id: "myOtherObj" } property var lastFactoryObj + QtObject{ id: bar; objectName: "bar" } + QtObject{ id: baz; objectName: "baz" } QtObject { id: myFactory function create(id) @@ -74,9 +76,13 @@ TestCase { lastFactoryObj = component.createObject(myFactory, {objectName: id}); return lastFactoryObj; } + property var objectInProperty: QtObject { + objectName: "foo" + } + property var otherObject: myObj + property var objects: [ bar, baz ]; WebChannel.id: "myFactory" } - Component { id: component QtObject { @@ -276,6 +282,15 @@ TestCase { lastFactoryObj.mySignal("foobar", 42); client.awaitSignal(); + // property should be wrapped + compare(channel.objects.myFactory.objectInProperty.objectName, "foo"); + // list property as well + compare(channel.objects.myFactory.objects.length, 2); + compare(channel.objects.myFactory.objects[0].objectName, "bar"); + compare(channel.objects.myFactory.objects[1].objectName, "baz"); + // also works with properties that reference other registered objects + compare(channel.objects.myFactory.otherObject, channel.objects.myObj); + // deleteLater call msg = client.awaitMessage(); compare(msg.type, JSClient.QWebChannelMessageTypes.invokeMethod); diff --git a/tests/auto/qml/tst_webchannelseparation.qml b/tests/auto/qml/tst_webchannelseparation.qml index 289f8b2..8a74243 100644 --- a/tests/auto/qml/tst_webchannelseparation.qml +++ b/tests/auto/qml/tst_webchannelseparation.qml @@ -91,15 +91,16 @@ TestCase { } WebChannel.id: "myObj3" } + + property var lastFactoryObj + property var createdFactoryObjects: [] QtObject { id: myFactory - property var lastObj - property var createdObjects: [] function cleanup() { - while (createdObjects.length) { - var obj = createdObjects.shift(); + while (createdFactoryObjects.length) { + var obj = createdFactoryObjects.shift(); if (obj) { obj.destroy(); } @@ -108,9 +109,9 @@ TestCase { function create(id) { - lastObj = component.createObject(myFactory, {objectName: id}); - createdObjects.push(lastObj); - return lastObj; + lastFactoryObj = component.createObject(myFactory, {objectName: id}); + createdFactoryObjects.push(lastFactoryObj); + return lastFactoryObj; } WebChannel.id: "myFactory" } @@ -146,7 +147,8 @@ TestCase { client2.debug = false; // delete all created objects myFactory.cleanup(); - myFactory.lastObj = undefined; + lastFactoryObj = undefined; + createdFactoryObjects = []; // reschedule current task to end of event loop wait(1); } @@ -160,7 +162,7 @@ TestCase { var channel1 = client1.createChannel(function (channel1) { channel1.objects.myFactory.create("testObj1", function (obj1) { - testObj1 = myFactory.lastObj; + testObj1 = lastFactoryObj; testObj1Id = obj1.__id__; obj1.mySignal.connect(function (arg1_1, arg1_2) { @@ -182,7 +184,7 @@ TestCase { channel2 = client2.createChannel(function (channel2) { channel2.objects.myFactory.create("testObj2", function (obj2) { - testObj2 = myFactory.lastObj; + testObj2 = lastFactoryObj; testObj2Id = obj2.__id__; obj2.mySignal.connect(function (arg2_1, arg2_2) { console.debug("client 2 received signal 'mySignal'"); @@ -278,7 +280,7 @@ TestCase { var channel1 = client1.createChannel(function (channel1) { channel1.objects.myFactory.create("testObj1", function (obj1) { - testObj1 = myFactory.lastObj; + testObj1 = lastFactoryObj; testObj1Id = obj1.__id__; obj1.myPropertyChanged.connect(function (arg1_1) { @@ -300,7 +302,7 @@ TestCase { channel2 = client2.createChannel(function (channel2) { channel2.objects.myFactory.create("testObj2", function (obj2) { - testObj2 = myFactory.lastObj; + testObj2 = lastFactoryObj; testObj2Id = obj2.__id__; obj2.myPropertyChanged.connect(function (arg1_1) { console.debug("client 2 received property update 'myProperty' " + obj2.myProperty); diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index 5060028..3d77b42 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -83,13 +83,37 @@ void TestWebChannel::testRegisterObjects() channel.registerObjects(objects); } +void TestWebChannel::testDeregisterObjects() +{ + QWebChannel channel; + TestObject testObject; + testObject.setObjectName("myTestObject"); + + + channel.registerObject(testObject.objectName(), &testObject); + + channel.connectTo(m_dummyTransport); + channel.d_func()->publisher->initializeClient(m_dummyTransport); + + QJsonObject connectMessage = + QJsonDocument::fromJson(("{\"type\": 7," + "\"object\": \"myTestObject\"," + "\"signal\": " + QString::number(testObject.metaObject()->indexOfSignal("sig1()")) + + "}").toLatin1()).object(); + channel.d_func()->publisher->handleMessage(connectMessage, m_dummyTransport); + + emit testObject.sig1(); + channel.deregisterObject(&testObject); + emit testObject.sig1(); +} + void TestWebChannel::testInfoForObject() { TestObject obj; obj.setObjectName("myTestObject"); QWebChannel channel; - const QJsonObject info = channel.d_func()->publisher->classInfoForObject(&obj); + const QJsonObject info = channel.d_func()->publisher->classInfoForObject(&obj, m_dummyTransport); QCOMPARE(info.keys(), QStringList() << "enums" << "methods" << "properties" << "signals"); @@ -267,7 +291,7 @@ void TestWebChannel::benchClassInfo() QBENCHMARK { foreach (const QObject *object, objects) { - channel.d_func()->publisher->classInfoForObject(object); + channel.d_func()->publisher->classInfoForObject(object, m_dummyTransport); } } } @@ -282,7 +306,7 @@ void TestWebChannel::benchInitializeClients() QMetaObjectPublisher *publisher = channel.d_func()->publisher; QBENCHMARK { - publisher->initializeClient(); + publisher->initializeClient(m_dummyTransport); publisher->propertyUpdatesInitialized = false; publisher->signalToPropertyMap.clear(); @@ -304,7 +328,7 @@ void TestWebChannel::benchPropertyUpdates() } channel.registerObjects(objects); - channel.d_func()->publisher->initializeClient(); + channel.d_func()->publisher->initializeClient(m_dummyTransport); QBENCHMARK { foreach (BenchObject *obj, objectList) { diff --git a/tests/auto/webchannel/tst_webchannel.h b/tests/auto/webchannel/tst_webchannel.h index ad8c6a4..6564944 100644 --- a/tests/auto/webchannel/tst_webchannel.h +++ b/tests/auto/webchannel/tst_webchannel.h @@ -214,6 +214,7 @@ public: private slots: void testRegisterObjects(); + void testDeregisterObjects(); void testInfoForObject(); void testInvokeMethodConversion(); void testDisconnect(); |