diff options
Diffstat (limited to 'tests/auto/webchannel/tst_webchannel.cpp')
-rw-r--r-- | tests/auto/webchannel/tst_webchannel.cpp | 261 |
1 files changed, 261 insertions, 0 deletions
diff --git a/tests/auto/webchannel/tst_webchannel.cpp b/tests/auto/webchannel/tst_webchannel.cpp index 55fd2d9..f1911e5 100644 --- a/tests/auto/webchannel/tst_webchannel.cpp +++ b/tests/auto/webchannel/tst_webchannel.cpp @@ -38,9 +38,156 @@ #include <qmetaobjectpublisher_p.h> #include <QtTest> +#ifdef WEBCHANNEL_TESTS_CAN_USE_JS_ENGINE +#include <QJSEngine> +#endif QT_USE_NAMESPACE +#ifdef WEBCHANNEL_TESTS_CAN_USE_JS_ENGINE +class TestJSEngine; + +class TestEngineTransport : public QWebChannelAbstractTransport +{ + Q_OBJECT +public: + TestEngineTransport(TestJSEngine *); + void sendMessage(const QJsonObject &message) Q_DECL_OVERRIDE; + + Q_INVOKABLE void channelSetupReady(); + Q_INVOKABLE void send(const QByteArray &message); +private: + TestJSEngine *m_testEngine; +}; + +class ConsoleLogger : public QObject +{ + Q_OBJECT +public: + ConsoleLogger(QObject *parent = 0); + + Q_INVOKABLE void log(const QString &text); + Q_INVOKABLE void error(const QString &text); + + int errorCount() const { return m_errCount; } + int logCount() const { return m_logCount; } + QString lastError() const { return m_lastError; } + +private: + int m_errCount; + int m_logCount; + QString m_lastError; + +}; + + + +ConsoleLogger::ConsoleLogger(QObject *parent) + : QObject(parent) + , m_errCount(0) + , m_logCount(0) +{ +} + +void ConsoleLogger::log(const QString &text) +{ + m_logCount++; + qDebug("LOG: %s", qPrintable(text)); +} + +void ConsoleLogger::error(const QString &text) +{ + m_errCount++; + m_lastError = text; + qWarning("ERROR: %s", qPrintable(text)); +} + + +// A test JS engine with convenience integration with WebChannel. +class TestJSEngine : public QJSEngine +{ + Q_OBJECT +public: + TestJSEngine(); + + TestEngineTransport *transport() const; + ConsoleLogger *logger() const; + void initWebChannelJS(); + +signals: + void channelSetupReady(TestEngineTransport *transport); + +private: + TestEngineTransport *m_transport; + ConsoleLogger *m_logger; +}; + +TestEngineTransport::TestEngineTransport(TestJSEngine *engine) + : QWebChannelAbstractTransport(engine) + , m_testEngine(engine) +{ +} + +void TestEngineTransport::sendMessage(const QJsonObject &message) +{ + QByteArray json = QJsonDocument(message).toJson(QJsonDocument::Compact); + QJSValue callback = m_testEngine->evaluate(QStringLiteral("transport.onmessage")); + Q_ASSERT(callback.isCallable()); + QJSValue arg = m_testEngine->newObject(); + QJSValue data = m_testEngine->evaluate(QString::fromLatin1("JSON.parse('%1');").arg(QString::fromUtf8(json))); + Q_ASSERT(!data.isError()); + arg.setProperty(QStringLiteral("data"), data); + QJSValue val = callback.call((QJSValueList() << arg)); + Q_ASSERT(!val.isError()); +} + +void TestEngineTransport::channelSetupReady() +{ + emit m_testEngine->channelSetupReady(m_testEngine->transport()); +} + +void TestEngineTransport::send(const QByteArray &message) +{ + QJsonDocument doc(QJsonDocument::fromJson(message)); + emit messageReceived(doc.object(), this); +} + + +TestJSEngine::TestJSEngine() + : m_transport(new TestEngineTransport(this)) + , m_logger(new ConsoleLogger(this)) +{ + globalObject().setProperty("transport", newQObject(m_transport)); + globalObject().setProperty("console", newQObject(m_logger)); + + QString webChannelJSPath(QStringLiteral(":/qtwebchannel/qwebchannel.js")); + QFile webChannelJS(webChannelJSPath); + if (!webChannelJS.open(QFile::ReadOnly)) + qFatal("Error opening qwebchannel.js"); + QString source(QString::fromUtf8(webChannelJS.readAll())); + evaluate(source, webChannelJSPath); +} + +TestEngineTransport *TestJSEngine::transport() const +{ + return m_transport; +} + +ConsoleLogger *TestJSEngine::logger() const +{ + return m_logger; +} + +void TestJSEngine::initWebChannelJS() +{ + globalObject().setProperty(QStringLiteral("channel"), newObject()); + QJSValue channel = evaluate(QStringLiteral("channel = new QWebChannel(transport, function(channel) { transport.channelSetupReady();});")); + Q_ASSERT(!channel.isError()); +} + +#endif // WEBCHANNEL_TESTS_CAN_USE_JS_ENGINE + + TestWebChannel::TestWebChannel(QObject *parent) : QObject(parent) , m_dummyTransport(new DummyTransport(this)) @@ -148,6 +295,12 @@ void TestWebChannel::testInfoForObject() } { QJsonArray method; + method.append(QStringLiteral("setObjectProperty")); + method.append(obj.metaObject()->indexOfMethod("setObjectProperty(QObject*)")); + expected.append(method); + } + { + QJsonArray method; method.append(QStringLiteral("method1")); method.append(obj.metaObject()->indexOfMethod("method1()")); expected.append(method); @@ -230,6 +383,19 @@ void TestWebChannel::testInfoForObject() property.append(obj.bar()); expected.append(property); } + { + QJsonArray property; + property.append(obj.metaObject()->indexOfProperty("objectProperty")); + property.append(QStringLiteral("objectProperty")); + { + QJsonArray signal; + signal.append(1); + signal.append(obj.metaObject()->indexOfMethod("objectPropertyChanged()")); + property.append(signal); + } + property.append(QJsonValue::fromVariant(QVariant::fromValue(obj.objectProperty()))); + expected.append(property); + } QCOMPARE(info["properties"].toArray(), expected); } } @@ -270,6 +436,43 @@ void TestWebChannel::testDisconnect() m_dummyTransport->emitMessageReceived(QJsonObject()); } +void TestWebChannel::testWrapRegisteredObject() +{ + QWebChannel channel; + TestObject obj; + obj.setObjectName("myTestObject"); + + channel.registerObject(obj.objectName(), &obj); + channel.connectTo(m_dummyTransport); + channel.d_func()->publisher->initializeClient(m_dummyTransport); + + QJsonObject objectInfo = channel.d_func()->publisher->wrapResult(QVariant::fromValue(&obj), m_dummyTransport).toObject(); + + QCOMPARE(2, objectInfo.length()); + QVERIFY(objectInfo.contains("id")); + QVERIFY(objectInfo.contains("__QObject*__")); + QVERIFY(objectInfo.value("__QObject*__").isBool() && objectInfo.value("__QObject*__").toBool()); + + QString returnedId = objectInfo.value("id").toString(); + + QCOMPARE(&obj, channel.d_func()->publisher->registeredObjects.value(obj.objectName())); + QCOMPARE(obj.objectName(), channel.d_func()->publisher->registeredObjectIds.value(&obj)); + QCOMPARE(obj.objectName(), returnedId); +} + +void TestWebChannel::testInfiniteRecursion() +{ + QWebChannel channel; + TestObject obj; + obj.setObjectProperty(&obj); + obj.setObjectName("myTestObject"); + + channel.connectTo(m_dummyTransport); + channel.d_func()->publisher->initializeClient(m_dummyTransport); + + QJsonObject objectInfo = channel.d_func()->publisher->wrapResult(QVariant::fromValue(&obj), m_dummyTransport).toObject(); +} + static QHash<QString, QObject*> createObjects(QObject *parent) { const int num = 100; @@ -352,5 +555,63 @@ void TestWebChannel::benchRegisterObjects() channel.registerObjects(objects); } } +#ifdef WEBCHANNEL_TESTS_CAN_USE_JS_ENGINE +class SubclassedTestObject : public TestObject +{ + Q_OBJECT + Q_PROPERTY(QString bar READ bar WRITE setBar NOTIFY theBarHasChanged) +public: + void setBar(const QString &newBar); +signals: + void theBarHasChanged(); +}; + +void SubclassedTestObject::setBar(const QString &newBar) +{ + if (!newBar.isNull()) + emit theBarHasChanged(); +} + +class TestSubclassedFunctor { +public: + TestSubclassedFunctor(TestJSEngine *engine) + : m_engine(engine) + { + } + + void operator()() { + QCOMPARE(m_engine->logger()->errorCount(), 0); + } + +private: + TestJSEngine *m_engine; +}; +#endif // WEBCHANNEL_TESTS_CAN_USE_JS_ENGINE + +void TestWebChannel::qtbug46548_overriddenProperties() +{ +#ifndef WEBCHANNEL_TESTS_CAN_USE_JS_ENGINE + QSKIP("A JS engine is required for this test to make sense."); +#else + SubclassedTestObject obj; + obj.setObjectName("subclassedTestObject"); + + QWebChannel webChannel; + webChannel.registerObject(obj.objectName(), &obj); + TestJSEngine engine; + webChannel.connectTo(engine.transport()); + QSignalSpy spy(&engine, &TestJSEngine::channelSetupReady); + connect(&engine, &TestJSEngine::channelSetupReady, TestSubclassedFunctor(&engine)); + engine.initWebChannelJS(); + if (!spy.count()) + spy.wait(); + QCOMPARE(spy.count(), 1); + QJSValue subclassedTestObject = engine.evaluate("channel.objects[\"subclassedTestObject\"]"); + QVERIFY(subclassedTestObject.isObject()); + +#endif // WEBCHANNEL_TESTS_CAN_USE_JS_ENGINE +} QTEST_MAIN(TestWebChannel) + +#include "tst_webchannel.moc" |