1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28#include <QtCore/QObject>
29#include <QtCore/QVariant>
30#include <QtCore/QList>
31#include <QtCore/QVector>
32#include <QtTest/QtTest>
33#include <QtDBus>
34
35
36class tst_QDBusLocalCalls: public QObject
37{
38 Q_OBJECT
39 Q_CLASSINFO("D-Bus Interface", "local.tst_QDBusLocalCalls")
40
41 QDBusConnection conn;
42public:
43 tst_QDBusLocalCalls();
44
45public Q_SLOTS:
46 Q_SCRIPTABLE int echo(int value)
47 { return value; }
48
49 Q_SCRIPTABLE QString echo(const QString &value)
50 { return value; }
51
52 Q_SCRIPTABLE QDBusVariant echo(const QDBusVariant &value)
53 { return value; }
54
55 Q_SCRIPTABLE QVector<int> echo(const QVector<int> &value)
56 { return value; }
57
58 Q_SCRIPTABLE QString echo2(const QStringList &list, QString &out)
59 { out = list[1]; return list[0]; }
60
61 Q_SCRIPTABLE void delayed(const QDBusMessage &msg)
62 { msg.setDelayedReply(true); }
63
64protected Q_SLOTS:
65 void replyReceived(QDBusPendingCallWatcher *watcher);
66
67private Q_SLOTS:
68 void initTestCase();
69 void makeInvalidCalls();
70 void makeCalls_data();
71 void makeCalls();
72 void makeCallsVariant_data();
73 void makeCallsVariant();
74 void makeCallsTwoRets();
75 void makeCallsComplex();
76 void makeDelayedCalls();
77 void asyncReplySignal();
78
79private:
80 QVariantList asyncReplyArgs;
81 QDBusMessage doCall(const QDBusMessage &call);
82};
83
84tst_QDBusLocalCalls::tst_QDBusLocalCalls()
85 : conn(QDBusConnection::sessionBus())
86{
87}
88
89QDBusMessage tst_QDBusLocalCalls::doCall(const QDBusMessage &call)
90{
91 QFETCH_GLOBAL(bool, useAsync);
92 if (useAsync) {
93 QDBusPendingCall ac = conn.asyncCall(message: call);
94 ac.waitForFinished();
95 return ac.reply();
96 } else {
97 return conn.call(message: call);
98 }
99}
100
101void tst_QDBusLocalCalls::replyReceived(QDBusPendingCallWatcher *watcher)
102{
103 asyncReplyArgs = watcher->reply().arguments();
104 QTestEventLoop::instance().exitLoop();
105}
106
107void tst_QDBusLocalCalls::initTestCase()
108{
109 QVERIFY(conn.isConnected());
110 QVERIFY(conn.registerObject("/", this, QDBusConnection::ExportScriptableSlots));
111
112 QTest::addColumn<bool>(name: "useAsync");
113 QTest::newRow(dataTag: "sync") << false;
114 QTest::newRow(dataTag: "async") << true;
115}
116
117void tst_QDBusLocalCalls::makeCalls_data()
118{
119 QTest::addColumn<QVariant>(name: "value");
120 QTest::newRow(dataTag: "int") << QVariant(42);
121 QTest::newRow(dataTag: "string") << QVariant("Hello, world");
122}
123
124void tst_QDBusLocalCalls::makeCallsVariant_data()
125{
126 makeCalls_data();
127}
128
129void tst_QDBusLocalCalls::makeInvalidCalls()
130{
131 {
132 QDBusMessage callMsg = QDBusMessage::createMethodCall(destination: conn.baseService(),
133 path: "/", interface: QString(), method: "echo");
134 QDBusMessage replyMsg = doCall(call: callMsg);
135 QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage));
136
137 QDBusError error(replyMsg);
138 QCOMPARE(int(error.type()), int(QDBusError::UnknownMethod));
139 }
140
141 {
142 QDBusMessage callMsg = QDBusMessage::createMethodCall(destination: conn.baseService(),
143 path: "/no_object", interface: QString(), method: "echo");
144 QDBusMessage replyMsg = doCall(call: callMsg);
145 QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage));
146
147 QDBusError error(replyMsg);
148 QCOMPARE(int(error.type()), int(QDBusError::UnknownObject));
149 }
150}
151
152void tst_QDBusLocalCalls::makeCalls()
153{
154 QFETCH(QVariant, value);
155 QDBusMessage callMsg = QDBusMessage::createMethodCall(destination: conn.baseService(),
156 path: "/", interface: QString(), method: "echo");
157 callMsg << value;
158 QDBusMessage replyMsg = doCall(call: callMsg);
159
160 QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
161
162 QVariantList replyArgs = replyMsg.arguments();
163 QCOMPARE(replyArgs.count(), 1);
164 QCOMPARE(replyArgs.at(0), value);
165}
166
167void tst_QDBusLocalCalls::makeCallsVariant()
168{
169 QFETCH(QVariant, value);
170 QDBusMessage callMsg = QDBusMessage::createMethodCall(destination: conn.baseService(),
171 path: "/", interface: QString(), method: "echo");
172 callMsg << QVariant::fromValue(value: QDBusVariant(value));
173 QDBusMessage replyMsg = doCall(call: callMsg);
174
175 QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
176
177 QVariantList replyArgs = replyMsg.arguments();
178 QCOMPARE(replyArgs.count(), 1);
179
180 const QVariant &reply = replyArgs.at(i: 0);
181 QCOMPARE(reply.userType(), qMetaTypeId<QDBusVariant>());
182 QCOMPARE(qvariant_cast<QDBusVariant>(reply).variant(), value);
183}
184
185void tst_QDBusLocalCalls::makeCallsTwoRets()
186{
187 QDBusMessage callMsg = QDBusMessage::createMethodCall(destination: conn.baseService(),
188 path: "/", interface: QString(), method: "echo2");
189 callMsg << (QStringList() << "One" << "Two");
190 QDBusMessage replyMsg = doCall(call: callMsg);
191
192 QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
193
194 QVariantList replyArgs = replyMsg.arguments();
195 QCOMPARE(replyArgs.count(), 2);
196 QCOMPARE(replyArgs.at(0).toString(), QString::fromLatin1("One"));
197 QCOMPARE(replyArgs.at(1).toString(), QString::fromLatin1("Two"));
198}
199
200void tst_QDBusLocalCalls::makeCallsComplex()
201{
202 qDBusRegisterMetaType<QList<int> >();
203 qDBusRegisterMetaType<QVector<int> >();
204
205 QList<int> value;
206 value << 1 << -42 << 47;
207 QDBusMessage callMsg = QDBusMessage::createMethodCall(destination: conn.baseService(),
208 path: "/", interface: QString(), method: "echo");
209 callMsg << QVariant::fromValue(value);
210 QDBusMessage replyMsg = doCall(call: callMsg);
211
212 QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ReplyMessage));
213
214 QVariantList replyArgs = replyMsg.arguments();
215 QCOMPARE(replyArgs.count(), 1);
216 const QVariant &reply = replyArgs.at(i: 0);
217 QCOMPARE(reply.userType(), qMetaTypeId<QDBusArgument>());
218 QCOMPARE(qdbus_cast<QList<int> >(reply), value);
219}
220
221void tst_QDBusLocalCalls::makeDelayedCalls()
222{
223 QDBusMessage callMsg = QDBusMessage::createMethodCall(destination: conn.baseService(),
224 path: "/", interface: QString(), method: "delayed");
225 QTest::ignoreMessage(type: QtWarningMsg, message: "QDBusConnection: cannot call local method 'delayed' at object / (with signature '') on blocking mode");
226 QDBusMessage replyMsg = doCall(call: callMsg);
227 QCOMPARE(int(replyMsg.type()), int(QDBusMessage::ErrorMessage));
228
229 QDBusError error(replyMsg);
230 QCOMPARE(int(error.type()), int(QDBusError::InternalError));
231}
232
233void tst_QDBusLocalCalls::asyncReplySignal()
234{
235 QFETCH_GLOBAL(bool, useAsync);
236 if (!useAsync)
237 return; // this test only works in async mode
238
239 QDBusMessage callMsg = QDBusMessage::createMethodCall(destination: conn.baseService(),
240 path: "/", interface: QString(), method: "echo");
241 callMsg << "Hello World";
242 QDBusPendingCall ac = conn.asyncCall(message: callMsg);
243 if (ac.isFinished())
244 QSKIP("Test ignored: the local-loop async call is already finished");
245
246 QDBusPendingCallWatcher watch(ac);
247 connect(asender: &watch, SIGNAL(finished(QDBusPendingCallWatcher*)),
248 SLOT(replyReceived(QDBusPendingCallWatcher*)));
249
250 QTestEventLoop::instance().enterLoop(secs: 2);
251 QVERIFY(!QTestEventLoop::instance().timeout());
252
253 QVERIFY(ac.isFinished());
254 QVERIFY(!ac.isError());
255
256 QVERIFY(!asyncReplyArgs.isEmpty());
257 QCOMPARE(asyncReplyArgs.at(0).toString(), QString("Hello World"));
258}
259
260QTEST_MAIN(tst_QDBusLocalCalls)
261#include "tst_qdbuslocalcalls.moc"
262

source code of qtbase/tests/auto/dbus/qdbuslocalcalls/tst_qdbuslocalcalls.cpp