From 28d8736caf695b47f9d4bc0bdbfeb751598a310c Mon Sep 17 00:00:00 2001 From: Ivailo Monev Date: Wed, 29 Jan 2020 01:47:55 +0000 Subject: [PATCH] add QDBusLocalCalls test --- tests/auto/qdbuslocalcalls/CMakeLists.txt | 7 + tests/auto/qdbuslocalcalls/tst_qdbuslocalcalls.cpp | 271 +++++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 tests/auto/qdbuslocalcalls/CMakeLists.txt create mode 100644 tests/auto/qdbuslocalcalls/tst_qdbuslocalcalls.cpp diff --git a/tests/auto/qdbuslocalcalls/CMakeLists.txt b/tests/auto/qdbuslocalcalls/CMakeLists.txt new file mode 100644 index 000000000..1af0c1861 --- /dev/null +++ b/tests/auto/qdbuslocalcalls/CMakeLists.txt @@ -0,0 +1,7 @@ +if(WITH_DBUS AND DBUS_FOUND) + katie_test(tst_qdbuslocalcalls + ${CMAKE_CURRENT_SOURCE_DIR}/tst_qdbuslocalcalls.cpp + ) + + target_link_libraries(tst_qdbuslocalcalls KtDBus) +endif() \ No newline at end of file diff --git a/tests/auto/qdbuslocalcalls/tst_qdbuslocalcalls.cpp b/tests/auto/qdbuslocalcalls/tst_qdbuslocalcalls.cpp new file mode 100644 index 000000000..9e4e91985 --- /dev/null +++ b/tests/auto/qdbuslocalcalls/tst_qdbuslocalcalls.cpp @@ -0,0 +1,271 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd. +** Copyright (C) 2016-2020 Ivailo Monev +** +** This file is part of the test suite of the Katie Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** As a special exception, The Qt Company gives you certain additional +** rights. These rights are described in The Qt Company LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(QVariant) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QVector) + +class tst_QDBusLocalCalls: public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "local.tst_QDBusLocalCalls") + + QDBusConnection conn; +public: + tst_QDBusLocalCalls(); + +public Q_SLOTS: + Q_SCRIPTABLE int echo(int value) + { return value; } + + Q_SCRIPTABLE QString echo(const QString &value) + { return value; } + + Q_SCRIPTABLE QDBusVariant echo(const QDBusVariant &value) + { return value; } + + Q_SCRIPTABLE QVector echo(const QVector &value) + { return value; } + + Q_SCRIPTABLE QString echo2(const QStringList &list, QString &out) + { out = list[1]; return list[0]; } + + Q_SCRIPTABLE void delayed(QDBusMessage msg) + { msg.setDelayedReply(true); } + +protected Q_SLOTS: + void replyReceived(QDBusPendingCallWatcher *watcher); + +private Q_SLOTS: + void initTestCase(); + void makeInvalidCalls(); + void makeCalls_data(); + void makeCalls(); + void makeCallsVariant_data(); + void makeCallsVariant(); + void makeCallsTwoRets(); + void makeCallsComplex(); + void makeDelayedCalls(); + void asyncReplySignal(); + +private: + QVariantList asyncReplyArgs; + QDBusMessage doCall(const QDBusMessage &call); +}; + +tst_QDBusLocalCalls::tst_QDBusLocalCalls() + : conn(QDBusConnection::sessionBus()) +{ +} + +QDBusMessage tst_QDBusLocalCalls::doCall(const QDBusMessage &call) +{ + QFETCH_GLOBAL(bool, useAsync); + if (useAsync) { + QDBusPendingCall ac = conn.asyncCall(call); + ac.waitForFinished(); + return ac.reply(); + } else { + return conn.call(call); + } +} + +void tst_QDBusLocalCalls::replyReceived(QDBusPendingCallWatcher *watcher) +{ + asyncReplyArgs = watcher->reply().arguments(); + QTestEventLoop::instance().exitLoop(); +} + +void tst_QDBusLocalCalls::initTestCase() +{ + QVERIFY(conn.isConnected()); + QVERIFY(conn.registerObject("/", this, QDBusConnection::ExportScriptableSlots)); + + QTest::addColumn("useAsync"); + QTest::newRow("sync") << false; + QTest::newRow("async") << true; +} + +void tst_QDBusLocalCalls::makeCalls_data() +{ + QTest::addColumn("value"); + QTest::newRow("int") << QVariant(42); + QTest::newRow("string") << QVariant("Hello, world"); +} + +void tst_QDBusLocalCalls::makeCallsVariant_data() +{ + makeCalls_data(); +} + +void tst_QDBusLocalCalls::makeInvalidCalls() +{ + { + QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(), + "/", QString(), "echo"); + QDBusMessage replyMsg = doCall(callMsg); + QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage)); + + QDBusError error(replyMsg); + QCOMPARE(int(error.type()), int(QDBusError::UnknownMethod)); + } + + { + QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(), + "/no_object", QString(), "echo"); + QDBusMessage replyMsg = doCall(callMsg); + QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage)); + + QDBusError error(replyMsg); + QCOMPARE(int(error.type()), int(QDBusError::UnknownObject)); + } +} + +void tst_QDBusLocalCalls::makeCalls() +{ + QFETCH(QVariant, value); + QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(), + "/", QString(), "echo"); + callMsg << value; + QDBusMessage replyMsg = doCall(callMsg); + + QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage)); + + QVariantList replyArgs = replyMsg.arguments(); + QCOMPARE(replyArgs.count(), 1); + QCOMPARE(replyArgs.at(0), value); +} + +void tst_QDBusLocalCalls::makeCallsVariant() +{ + QFETCH(QVariant, value); + QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(), + "/", QString(), "echo"); + callMsg << qVariantFromValue(QDBusVariant(value)); + QDBusMessage replyMsg = doCall(callMsg); + + QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage)); + + QVariantList replyArgs = replyMsg.arguments(); + QCOMPARE(replyArgs.count(), 1); + + const QVariant &reply = replyArgs.at(0); + QCOMPARE(reply.userType(), qMetaTypeId()); + QCOMPARE(qvariant_cast(reply).variant(), value); +} + +void tst_QDBusLocalCalls::makeCallsTwoRets() +{ + QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(), + "/", QString(), "echo2"); + callMsg << (QStringList() << "One" << "Two"); + QDBusMessage replyMsg = doCall(callMsg); + + QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage)); + + QVariantList replyArgs = replyMsg.arguments(); + QCOMPARE(replyArgs.count(), 2); + QCOMPARE(replyArgs.at(0).toString(), QString::fromLatin1("One")); + QCOMPARE(replyArgs.at(1).toString(), QString::fromLatin1("Two")); +} + +void tst_QDBusLocalCalls::makeCallsComplex() +{ + qDBusRegisterMetaType >(); + qDBusRegisterMetaType >(); + + QList value; + value << 1 << -42 << 47; + QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(), + "/", QString(), "echo"); + callMsg << qVariantFromValue(value); + QDBusMessage replyMsg = doCall(callMsg); + + QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage)); + + QVariantList replyArgs = replyMsg.arguments(); + QCOMPARE(replyArgs.count(), 1); + const QVariant &reply = replyArgs.at(0); + QCOMPARE(reply.userType(), qMetaTypeId()); + QCOMPARE(qdbus_cast >(reply), value); +} + +void tst_QDBusLocalCalls::makeDelayedCalls() +{ + QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(), + "/", QString(), "delayed"); + QTest::ignoreMessage(QtWarningMsg, "QDBusConnection: cannot call local method 'delayed' at object / (with signature '') on blocking mode"); + QDBusMessage replyMsg = doCall(callMsg); + QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage)); + + QDBusError error(replyMsg); + QCOMPARE(int(error.type()), int(QDBusError::InternalError)); +} + +void tst_QDBusLocalCalls::asyncReplySignal() +{ + QFETCH_GLOBAL(bool, useAsync); + if (!useAsync) + return; // this test only works in async mode + + QDBusMessage callMsg = QDBusMessage::createMethodCall(conn.baseService(), + "/", QString(), "echo"); + callMsg << "Hello World"; + QDBusPendingCall ac = conn.asyncCall(callMsg); + if (ac.isFinished()) + QSKIP("Test ignored: the local-loop async call is already finished", SkipAll); + + QDBusPendingCallWatcher watch(ac); + connect(&watch, SIGNAL(finished(QDBusPendingCallWatcher*)), + SLOT(replyReceived(QDBusPendingCallWatcher*))); + + QTestEventLoop::instance().enterLoop(2); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QVERIFY(ac.isFinished()); + QVERIFY(!ac.isError()); + + QVERIFY(!asyncReplyArgs.isEmpty()); + QCOMPARE(asyncReplyArgs.at(0).toString(), QString("Hello World")); +} + +QTEST_MAIN(tst_QDBusLocalCalls) + +#include "moc_tst_qdbuslocalcalls.cpp" -- 2.11.0