1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29#include <QtCore/QtCore>
30#include <QtTest/QtTest>
31#include <QtDBus/QtDBus>
32
33#include "common.h"
34#include <limits>
35
36#include <QtDBus/private/qdbusutil_p.h>
37#include <QtDBus/private/qdbusconnection_p.h>
38#include <QtDBus/private/qdbus_symbols_p.h>
39
40#ifndef DBUS_TYPE_UNIX_FD
41# define DBUS_TYPE_UNIX_FD int('h')
42# define DBUS_TYPE_UNIX_FD_AS_STRING "h"
43#endif
44
45static const char serviceName[] = "org.qtproject.autotests.qpong";
46static const char objectPath[] = "/org/qtproject/qpong";
47static const char *interfaceName = serviceName;
48
49class tst_QDBusMarshall: public QObject
50{
51 Q_OBJECT
52
53public slots:
54 void initTestCase();
55 void cleanupTestCase();
56
57private slots:
58 void sendBasic_data();
59 void sendBasic();
60
61 void sendVariant_data();
62 void sendVariant();
63
64 void sendArrays_data();
65 void sendArrays();
66
67 void sendArrayOfArrays_data();
68 void sendArrayOfArrays();
69
70 void sendMaps_data();
71 void sendMaps();
72
73 void sendStructs_data();
74 void sendStructs();
75
76 void sendComplex_data();
77 void sendComplex();
78
79 void sendArgument_data();
80 void sendArgument();
81
82 void sendSignalErrors();
83 void sendCallErrors_data();
84 void sendCallErrors();
85
86 void receiveUnknownType_data();
87 void receiveUnknownType();
88
89 void demarshallPrimitives_data();
90 void demarshallPrimitives();
91
92 void demarshallStrings_data();
93 void demarshallStrings();
94
95 void demarshallInvalidStringList_data();
96 void demarshallInvalidStringList();
97
98 void demarshallInvalidByteArray_data();
99 void demarshallInvalidByteArray();
100
101private:
102 int fileDescriptorForTest();
103
104 QProcess proc;
105 QTemporaryFile tempFile;
106 bool fileDescriptorPassing;
107};
108
109class QDBusMessageSpy: public QObject
110{
111 Q_OBJECT
112public slots:
113 Q_SCRIPTABLE int theSlot(const QDBusMessage &msg)
114 {
115 list << msg;
116 return 42;
117 }
118public:
119 QList<QDBusMessage> list;
120};
121
122struct UnregisteredType { };
123Q_DECLARE_METATYPE(UnregisteredType)
124
125void tst_QDBusMarshall::initTestCase()
126{
127 commonInit();
128 QDBusConnection con = QDBusConnection::sessionBus();
129 fileDescriptorPassing = con.connectionCapabilities() & QDBusConnection::UnixFileDescriptorPassing;
130
131#ifdef Q_OS_WIN
132# define EXE ".exe"
133#else
134# define EXE ""
135#endif
136 proc.setProcessChannelMode(QProcess::ForwardedErrorChannel);
137 proc.start(QFINDTESTDATA("qpong/qpong" EXE));
138 QVERIFY2(proc.waitForStarted(), qPrintable(proc.errorString()));
139 QVERIFY(proc.waitForReadyRead());
140}
141
142void tst_QDBusMarshall::cleanupTestCase()
143{
144 QDBusMessage msg = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath, interface: interfaceName, method: "quit");
145 QDBusConnection::sessionBus().call(message: msg);
146 proc.waitForFinished(msecs: 200);
147 proc.close();
148}
149
150int tst_QDBusMarshall::fileDescriptorForTest()
151{
152 if (!tempFile.isOpen()) {
153 tempFile.setFileTemplate(QDir::tempPath() + "/qdbusmarshalltestXXXXXX.tmp");
154 if (!tempFile.open()) {
155 qWarning(msg: "%s: Cannot create temporary file: %s", Q_FUNC_INFO,
156 qPrintable(tempFile.errorString()));
157 return 0;
158 }
159 }
160 return tempFile.handle();
161}
162
163void addBasicTypesColumns()
164{
165 QTest::addColumn<QVariant>(name: "value");
166 QTest::addColumn<QString>(name: "sig");
167 QTest::addColumn<QString>(name: "stringResult");
168}
169
170void basicNumericTypes_data()
171{
172 QTest::newRow(dataTag: "bool") << QVariant(false) << "b" << "false";
173 QTest::newRow(dataTag: "bool2") << QVariant(true) << "b" << "true";
174 QTest::newRow(dataTag: "byte") << QVariant::fromValue(value: uchar(1)) << "y" << "1";
175 QTest::newRow(dataTag: "int16") << QVariant::fromValue(value: short(2)) << "n" << "2";
176 QTest::newRow(dataTag: "uint16") << QVariant::fromValue(value: ushort(3)) << "q" << "3";
177 QTest::newRow(dataTag: "int") << QVariant(1) << "i" << "1";
178 QTest::newRow(dataTag: "uint") << QVariant(2U) << "u" << "2";
179 QTest::newRow(dataTag: "int64") << QVariant(Q_INT64_C(3)) << "x" << "3";
180 QTest::newRow(dataTag: "uint64") << QVariant(Q_UINT64_C(4)) << "t" << "4";
181 QTest::newRow(dataTag: "double") << QVariant(42.5) << "d" << "42.5";
182}
183
184void basicStringTypes_data()
185{
186 QTest::newRow(dataTag: "string") << QVariant("ping") << "s" << "\"ping\"";
187 QTest::newRow(dataTag: "objectpath") << QVariant::fromValue(value: QDBusObjectPath("/org/kde")) << "o" << "[ObjectPath: /org/kde]";
188 QTest::newRow(dataTag: "signature") << QVariant::fromValue(value: QDBusSignature("g")) << "g" << "[Signature: g]";
189 QTest::newRow(dataTag: "emptystring") << QVariant("") << "s" << "\"\"";
190 QTest::newRow(dataTag: "nullstring") << QVariant(QString()) << "s" << "\"\"";
191}
192
193void tst_QDBusMarshall::sendBasic_data()
194{
195 addBasicTypesColumns();
196
197 // basic types:
198 basicNumericTypes_data();
199 basicStringTypes_data();
200
201 if (fileDescriptorPassing)
202 QTest::newRow(dataTag: "file-descriptor") << QVariant::fromValue(value: QDBusUnixFileDescriptor(fileDescriptorForTest())) << "h" << "[Unix FD: valid]";
203}
204
205void tst_QDBusMarshall::sendVariant_data()
206{
207 sendBasic_data();
208
209 QTest::newRow(dataTag: "variant") << QVariant::fromValue(value: QDBusVariant(1)) << "v" << "[Variant(int): 1]";
210
211 QDBusVariant nested(1);
212 QTest::newRow(dataTag: "variant-variant") << QVariant::fromValue(value: QDBusVariant(QVariant::fromValue(value: nested))) << "v"
213 << "[Variant(QDBusVariant): [Variant(int): 1]]";
214}
215
216void tst_QDBusMarshall::sendArrays_data()
217{
218 QTest::addColumn<QVariant>(name: "value");
219 QTest::addColumn<QString>(name: "sig");
220 QTest::addColumn<QString>(name: "stringResult");
221
222 // arrays
223 QStringList strings;
224 QTest::newRow(dataTag: "emptystringlist") << QVariant(strings) << "as" << "{}";
225 strings << "hello" << "world";
226 QTest::newRow(dataTag: "stringlist") << QVariant(strings) << "as" << "{\"hello\", \"world\"}";
227
228 strings.clear();
229 strings << "" << "" << "";
230 QTest::newRow(dataTag: "list-of-emptystrings") << QVariant(strings) << "as" << "{\"\", \"\", \"\"}";
231
232 strings.clear();
233 strings << QString() << QString() << QString() << QString();
234 QTest::newRow(dataTag: "list-of-nullstrings") << QVariant(strings) << "as" << "{\"\", \"\", \"\", \"\"}";
235
236 QByteArray bytearray;
237 QTest::newRow(dataTag: "nullbytearray") << QVariant(bytearray) << "ay" << "{}";
238 bytearray = ""; // empty, not null
239 QTest::newRow(dataTag: "emptybytearray") << QVariant(bytearray) << "ay" << "{}";
240 bytearray = "foo";
241 QTest::newRow(dataTag: "bytearray") << QVariant(bytearray) << "ay" << "{102, 111, 111}";
242
243 QList<bool> bools;
244 QTest::newRow(dataTag: "emptyboollist") << QVariant::fromValue(value: bools) << "ab" << "[Argument: ab {}]";
245 bools << false << true << false;
246 QTest::newRow(dataTag: "boollist") << QVariant::fromValue(value: bools) << "ab" << "[Argument: ab {false, true, false}]";
247
248 QList<short> shorts;
249 QTest::newRow(dataTag: "emptyshortlist") << QVariant::fromValue(value: shorts) << "an" << "[Argument: an {}]";
250 shorts << 42 << -43 << 44 << 45 << -32768 << 32767;
251 QTest::newRow(dataTag: "shortlist") << QVariant::fromValue(value: shorts) << "an"
252 << "[Argument: an {42, -43, 44, 45, -32768, 32767}]";
253
254 QList<ushort> ushorts;
255 QTest::newRow(dataTag: "emptyushortlist") << QVariant::fromValue(value: ushorts) << "aq" << "[Argument: aq {}]";
256 ushorts << 12u << 13u << 14u << 15 << 65535;
257 QTest::newRow(dataTag: "ushortlist") << QVariant::fromValue(value: ushorts) << "aq" << "[Argument: aq {12, 13, 14, 15, 65535}]";
258
259 QList<int> ints;
260 QTest::newRow(dataTag: "emptyintlist") << QVariant::fromValue(value: ints) << "ai" << "[Argument: ai {}]";
261 ints << 42 << -43 << 44 << 45 << 2147483647 << -2147483647-1;
262 QTest::newRow(dataTag: "intlist") << QVariant::fromValue(value: ints) << "ai" << "[Argument: ai {42, -43, 44, 45, 2147483647, -2147483648}]";
263
264 QList<uint> uints;
265 QTest::newRow(dataTag: "emptyuintlist") << QVariant::fromValue(value: uints) << "au" << "[Argument: au {}]";
266 uints << uint(12) << uint(13) << uint(14) << 4294967295U;
267 QTest::newRow(dataTag: "uintlist") << QVariant::fromValue(value: uints) << "au" << "[Argument: au {12, 13, 14, 4294967295}]";
268
269 QList<qlonglong> llints;
270 QTest::newRow(dataTag: "emptyllintlist") << QVariant::fromValue(value: llints) << "ax" << "[Argument: ax {}]";
271 llints << Q_INT64_C(99) << Q_INT64_C(-100)
272 << Q_INT64_C(-9223372036854775807)-1 << Q_INT64_C(9223372036854775807);
273 QTest::newRow(dataTag: "llintlist") << QVariant::fromValue(value: llints) << "ax"
274 << "[Argument: ax {99, -100, -9223372036854775808, 9223372036854775807}]";
275
276 QList<qulonglong> ullints;
277 QTest::newRow(dataTag: "emptyullintlist") << QVariant::fromValue(value: ullints) << "at" << "[Argument: at {}]";
278 ullints << Q_UINT64_C(66) << Q_UINT64_C(67)
279 << Q_UINT64_C(18446744073709551615);
280 QTest::newRow(dataTag: "ullintlist") << QVariant::fromValue(value: ullints) << "at" << "[Argument: at {66, 67, 18446744073709551615}]";
281
282 QList<double> doubles;
283 QTest::newRow(dataTag: "emptydoublelist") << QVariant::fromValue(value: doubles) << "ad" << "[Argument: ad {}]";
284 doubles << 1.2 << 2.2 << 4.4
285 << -std::numeric_limits<double>::infinity()
286 << std::numeric_limits<double>::infinity()
287 << std::numeric_limits<double>::quiet_NaN();
288 QTest::newRow(dataTag: "doublelist") << QVariant::fromValue(value: doubles) << "ad" << "[Argument: ad {1.2, 2.2, 4.4, -inf, inf, nan}]";
289
290 QList<QDBusObjectPath> objectPaths;
291 QTest::newRow(dataTag: "emptyobjectpathlist") << QVariant::fromValue(value: objectPaths) << "ao" << "[Argument: ao {}]";
292 objectPaths << QDBusObjectPath("/") << QDBusObjectPath("/foo");
293 QTest::newRow(dataTag: "objectpathlist") << QVariant::fromValue(value: objectPaths) << "ao" << "[Argument: ao {[ObjectPath: /], [ObjectPath: /foo]}]";
294
295 if (fileDescriptorPassing) {
296 QList<QDBusUnixFileDescriptor> fileDescriptors;
297 QTest::newRow(dataTag: "emptyfiledescriptorlist") << QVariant::fromValue(value: fileDescriptors) << "ah" << "[Argument: ah {}]";
298 fileDescriptors << QDBusUnixFileDescriptor(fileDescriptorForTest()) << QDBusUnixFileDescriptor(1);
299 QTest::newRow(dataTag: "filedescriptorlist") << QVariant::fromValue(value: fileDescriptors) << "ah" << "[Argument: ah {[Unix FD: valid], [Unix FD: valid]}]";
300 }
301
302 QVariantList variants;
303 QTest::newRow(dataTag: "emptyvariantlist") << QVariant(variants) << "av" << "[Argument: av {}]";
304 variants << QString("Hello") << QByteArray("World") << 42 << -43.0 << 44U << Q_INT64_C(-45)
305 << Q_UINT64_C(46) << true << QVariant::fromValue(value: short(-47))
306 << QVariant::fromValue(value: QDBusSignature("av"))
307 << QVariant::fromValue(value: QDBusVariant(QVariant::fromValue(value: QDBusObjectPath("/"))));
308 QTest::newRow(dataTag: "variantlist") << QVariant(variants) << "av"
309 << "[Argument: av {[Variant(QString): \"Hello\"], [Variant(QByteArray): {87, 111, 114, 108, 100}], [Variant(int): 42], [Variant(double): -43], [Variant(uint): 44], [Variant(qlonglong): -45], [Variant(qulonglong): 46], [Variant(bool): true], [Variant(short): -47], [Variant: [Signature: av]], [Variant: [Variant: [ObjectPath: /]]]}]";
310}
311
312void tst_QDBusMarshall::sendArrayOfArrays_data()
313{
314 QTest::addColumn<QVariant>(name: "value");
315 QTest::addColumn<QString>(name: "sig");
316 QTest::addColumn<QString>(name: "stringResult");
317
318 // arrays:
319 QList<QStringList> strings;
320 QTest::newRow(dataTag: "empty-list-of-stringlist") << QVariant::fromValue(value: strings) << "aas"
321 << "[Argument: aas {}]";
322 strings << QStringList();
323 QTest::newRow(dataTag: "list-of-emptystringlist") << QVariant::fromValue(value: strings) << "aas"
324 << "[Argument: aas {{}}]";
325 strings << (QStringList() << "hello" << "world")
326 << (QStringList() << "hi" << "there")
327 << (QStringList() << QString());
328 QTest::newRow(dataTag: "stringlist") << QVariant::fromValue(value: strings) << "aas"
329 << "[Argument: aas {{}, {\"hello\", \"world\"}, {\"hi\", \"there\"}, {\"\"}}]";
330
331 QList<QByteArray> bytearray;
332 QTest::newRow(dataTag: "empty-list-of-bytearray") << QVariant::fromValue(value: bytearray) << "aay"
333 << "[Argument: aay {}]";
334 bytearray << QByteArray();
335 QTest::newRow(dataTag: "list-of-emptybytearray") << QVariant::fromValue(value: bytearray) << "aay"
336 << "[Argument: aay {{}}]";
337 bytearray << "foo" << "bar" << "baz" << "" << QByteArray();
338 QTest::newRow(dataTag: "bytearray") << QVariant::fromValue(value: bytearray) << "aay"
339 << "[Argument: aay {{}, {102, 111, 111}, {98, 97, 114}, {98, 97, 122}, {}, {}}]";
340
341 QList<QList<bool> > bools;
342 QTest::newRow(dataTag: "empty-list-of-boollist") << QVariant::fromValue(value: bools) << "aab"
343 << "[Argument: aab {}]";
344 bools << QList<bool>();
345 QTest::newRow(dataTag: "list-of-emptyboollist") << QVariant::fromValue(value: bools) << "aab"
346 << "[Argument: aab {[Argument: ab {}]}]";
347 bools << (QList<bool>() << false << true) << (QList<bool>() << false) << (QList<bool>());
348 QTest::newRow(dataTag: "boollist") << QVariant::fromValue(value: bools) << "aab"
349 << "[Argument: aab {[Argument: ab {}], [Argument: ab {false, true}], [Argument: ab {false}], [Argument: ab {}]}]";
350 QList<QList<short> > shorts;
351 QTest::newRow(dataTag: "empty-list-of-shortlist") << QVariant::fromValue(value: shorts) << "aan"
352 << "[Argument: aan {}]";
353 shorts << QList<short>();
354 QTest::newRow(dataTag: "list-of-emptyshortlist") << QVariant::fromValue(value: shorts) << "aan"
355 << "[Argument: aan {[Argument: an {}]}]";
356 shorts << (QList<short>() << 42 << -43 << 44 << 45)
357 << (QList<short>() << -32768 << 32767)
358 << (QList<short>());
359 QTest::newRow(dataTag: "shortlist") << QVariant::fromValue(value: shorts) << "aan"
360 << "[Argument: aan {[Argument: an {}], [Argument: an {42, -43, 44, 45}], [Argument: an {-32768, 32767}], [Argument: an {}]}]";
361
362 QList<QList<ushort> > ushorts;
363 QTest::newRow(dataTag: "empty-list-of-ushortlist") << QVariant::fromValue(value: ushorts) << "aaq"
364 << "[Argument: aaq {}]";
365 ushorts << QList<ushort>();
366 QTest::newRow(dataTag: "list-of-emptyushortlist") << QVariant::fromValue(value: ushorts) << "aaq"
367 << "[Argument: aaq {[Argument: aq {}]}]";
368 ushorts << (QList<ushort>() << 12u << 13u << 14u << 15)
369 << (QList<ushort>() << 65535)
370 << (QList<ushort>());
371 QTest::newRow(dataTag: "ushortlist") << QVariant::fromValue(value: ushorts) << "aaq"
372 << "[Argument: aaq {[Argument: aq {}], [Argument: aq {12, 13, 14, 15}], [Argument: aq {65535}], [Argument: aq {}]}]";
373
374 QList<QList<int> > ints;
375 QTest::newRow(dataTag: "empty-list-of-intlist") << QVariant::fromValue(value: ints) << "aai"
376 << "[Argument: aai {}]";
377 ints << QList<int>();
378 QTest::newRow(dataTag: "list-of-emptyintlist") << QVariant::fromValue(value: ints) << "aai"
379 << "[Argument: aai {[Argument: ai {}]}]";
380 ints << (QList<int>() << 42 << -43 << 44 << 45)
381 << (QList<int>() << 2147483647 << -2147483647-1)
382 << (QList<int>());
383 QTest::newRow(dataTag: "intlist") << QVariant::fromValue(value: ints) << "aai"
384 << "[Argument: aai {[Argument: ai {}], [Argument: ai {42, -43, 44, 45}], [Argument: ai {2147483647, -2147483648}], [Argument: ai {}]}]";
385
386 QList<QList<uint> > uints;
387 QTest::newRow(dataTag: "empty-list-of-uintlist") << QVariant::fromValue(value: uints) << "aau"
388 << "[Argument: aau {}]";
389 uints << QList<uint>();
390 QTest::newRow(dataTag: "list-of-emptyuintlist") << QVariant::fromValue(value: uints) << "aau"
391 << "[Argument: aau {[Argument: au {}]}]";
392 uints << (QList<uint>() << uint(12) << uint(13) << uint(14))
393 << (QList<uint>() << 4294967295U)
394 << (QList<uint>());
395 QTest::newRow(dataTag: "uintlist") << QVariant::fromValue(value: uints) << "aau"
396 << "[Argument: aau {[Argument: au {}], [Argument: au {12, 13, 14}], [Argument: au {4294967295}], [Argument: au {}]}]";
397
398 QList<QList<qlonglong> > llints;
399 QTest::newRow(dataTag: "empty-list-of-llintlist") << QVariant::fromValue(value: llints) << "aax"
400 << "[Argument: aax {}]";
401 llints << QList<qlonglong>();
402 QTest::newRow(dataTag: "list-of-emptyllintlist") << QVariant::fromValue(value: llints) << "aax"
403 << "[Argument: aax {[Argument: ax {}]}]";
404 llints << (QList<qlonglong>() << Q_INT64_C(99) << Q_INT64_C(-100))
405 << (QList<qlonglong>() << Q_INT64_C(-9223372036854775807)-1 << Q_INT64_C(9223372036854775807))
406 << (QList<qlonglong>());
407 QTest::newRow(dataTag: "llintlist") << QVariant::fromValue(value: llints) << "aax"
408 << "[Argument: aax {[Argument: ax {}], [Argument: ax {99, -100}], [Argument: ax {-9223372036854775808, 9223372036854775807}], [Argument: ax {}]}]";
409
410 QList<QList<qulonglong> > ullints;
411 QTest::newRow(dataTag: "empty-list-of-ullintlist") << QVariant::fromValue(value: ullints) << "aat"
412 << "[Argument: aat {}]";
413 ullints << QList<qulonglong>();
414 QTest::newRow(dataTag: "list-of-emptyullintlist") << QVariant::fromValue(value: ullints) << "aat"
415 << "[Argument: aat {[Argument: at {}]}]";
416 ullints << (QList<qulonglong>() << Q_UINT64_C(66) << Q_UINT64_C(67))
417 << (QList<qulonglong>() << Q_UINT64_C(18446744073709551615))
418 << (QList<qulonglong>());
419 QTest::newRow(dataTag: "ullintlist") << QVariant::fromValue(value: ullints) << "aat"
420 << "[Argument: aat {[Argument: at {}], [Argument: at {66, 67}], [Argument: at {18446744073709551615}], [Argument: at {}]}]";
421
422 QList<QList<double> > doubles;
423 QTest::newRow(dataTag: "empty-list-ofdoublelist") << QVariant::fromValue(value: doubles) << "aad"
424 << "[Argument: aad {}]";
425 doubles << QList<double>();
426 QTest::newRow(dataTag: "list-of-emptydoublelist") << QVariant::fromValue(value: doubles) << "aad"
427 << "[Argument: aad {[Argument: ad {}]}]";
428 doubles << (QList<double>() << 1.2 << 2.2 << 4.4)
429 << (QList<double>() << -std::numeric_limits<double>::infinity()
430 << std::numeric_limits<double>::infinity()
431 << std::numeric_limits<double>::quiet_NaN())
432 << (QList<double>());
433 QTest::newRow(dataTag: "doublelist") << QVariant::fromValue(value: doubles) << "aad"
434 << "[Argument: aad {[Argument: ad {}], [Argument: ad {1.2, 2.2, 4.4}], [Argument: ad {-inf, inf, nan}], [Argument: ad {}]}]";
435
436 QList<QVariantList> variants;
437 QTest::newRow(dataTag: "emptyvariantlist") << QVariant::fromValue(value: variants) << "aav"
438 << "[Argument: aav {}]";
439 variants << QVariantList();
440 QTest::newRow(dataTag: "emptyvariantlist") << QVariant::fromValue(value: variants) << "aav"
441 << "[Argument: aav {[Argument: av {}]}]";
442 variants << (QVariantList() << QString("Hello") << QByteArray("World"))
443 << (QVariantList() << 42 << -43.0 << 44U << Q_INT64_C(-45))
444 << (QVariantList() << Q_UINT64_C(46) << true << QVariant::fromValue(value: short(-47)));
445 QTest::newRow(dataTag: "variantlist") << QVariant::fromValue(value: variants) << "aav"
446 << "[Argument: aav {[Argument: av {}], [Argument: av {[Variant(QString): \"Hello\"], [Variant(QByteArray): {87, 111, 114, 108, 100}]}], [Argument: av {[Variant(int): 42], [Variant(double): -43], [Variant(uint): 44], [Variant(qlonglong): -45]}], [Argument: av {[Variant(qulonglong): 46], [Variant(bool): true], [Variant(short): -47]}]}]";
447}
448
449void tst_QDBusMarshall::sendMaps_data()
450{
451 QTest::addColumn<QVariant>(name: "value");
452 QTest::addColumn<QString>(name: "sig");
453 QTest::addColumn<QString>(name: "stringResult");
454
455 QMap<int, QString> ismap;
456 QTest::newRow(dataTag: "empty-is-map") << QVariant::fromValue(value: ismap) << "a{is}"
457 << "[Argument: a{is} {}]";
458 ismap[1] = "a";
459 ismap[2000] = "b";
460 ismap[-47] = "c";
461 QTest::newRow(dataTag: "is-map") << QVariant::fromValue(value: ismap) << "a{is}"
462 << "[Argument: a{is} {-47 = \"c\", 1 = \"a\", 2000 = \"b\"}]";
463
464 QMap<QString, QString> ssmap;
465 QTest::newRow(dataTag: "empty-ss-map") << QVariant::fromValue(value: ssmap) << "a{ss}"
466 << "[Argument: a{ss} {}]";
467 ssmap["a"] = "a";
468 ssmap["c"] = "b";
469 ssmap["b"] = "c";
470 QTest::newRow(dataTag: "ss-map") << QVariant::fromValue(value: ssmap) << "a{ss}"
471 << "[Argument: a{ss} {\"a\" = \"a\", \"b\" = \"c\", \"c\" = \"b\"}]";
472
473 QVariantMap svmap;
474 QTest::newRow(dataTag: "empty-sv-map") << QVariant::fromValue(value: svmap) << "a{sv}"
475 << "[Argument: a{sv} {}]";
476 svmap["a"] = 1;
477 svmap["c"] = "b";
478 svmap["b"] = QByteArray("c");
479 svmap["d"] = 42U;
480 svmap["e"] = QVariant::fromValue(value: short(-47));
481 svmap["f"] = QVariant::fromValue(value: QDBusVariant(0));
482 QTest::newRow(dataTag: "sv-map1") << QVariant::fromValue(value: svmap) << "a{sv}"
483 << "[Argument: a{sv} {\"a\" = [Variant(int): 1], \"b\" = [Variant(QByteArray): {99}], \"c\" = [Variant(QString): \"b\"], \"d\" = [Variant(uint): 42], \"e\" = [Variant(short): -47], \"f\" = [Variant: [Variant(int): 0]]}]";
484
485 QMap<QDBusObjectPath, QString> osmap;
486 QTest::newRow(dataTag: "empty-os-map") << QVariant::fromValue(value: osmap) << "a{os}"
487 << "[Argument: a{os} {}]";
488 osmap[QDBusObjectPath("/")] = "root";
489 osmap[QDBusObjectPath("/foo")] = "foo";
490 osmap[QDBusObjectPath("/bar/baz")] = "bar and baz";
491 QTest::newRow(dataTag: "os-map") << QVariant::fromValue(value: osmap) << "a{os}"
492 << "[Argument: a{os} {[ObjectPath: /] = \"root\", [ObjectPath: /bar/baz] = \"bar and baz\", [ObjectPath: /foo] = \"foo\"}]";
493
494 QMap<QDBusSignature, QString> gsmap;
495 QTest::newRow(dataTag: "empty-gs-map") << QVariant::fromValue(value: gsmap) << "a{gs}"
496 << "[Argument: a{gs} {}]";
497 gsmap[QDBusSignature("i")] = "int32";
498 gsmap[QDBusSignature("s")] = "string";
499 gsmap[QDBusSignature("a{gs}")] = "array of dict_entry of (signature, string)";
500 QTest::newRow(dataTag: "gs-map") << QVariant::fromValue(value: gsmap) << "a{gs}"
501 << "[Argument: a{gs} {[Signature: a{gs}] = \"array of dict_entry of (signature, string)\", [Signature: i] = \"int32\", [Signature: s] = \"string\"}]";
502
503 if (fileDescriptorPassing) {
504 svmap["zzfiledescriptor"] = QVariant::fromValue(value: QDBusUnixFileDescriptor(fileDescriptorForTest()));
505 QTest::newRow(dataTag: "sv-map1-fd") << QVariant::fromValue(value: svmap) << "a{sv}"
506 << "[Argument: a{sv} {\"a\" = [Variant(int): 1], \"b\" = [Variant(QByteArray): {99}], \"c\" = [Variant(QString): \"b\"], \"d\" = [Variant(uint): 42], \"e\" = [Variant(short): -47], \"f\" = [Variant: [Variant(int): 0]], \"zzfiledescriptor\" = [Variant(QDBusUnixFileDescriptor): [Unix FD: valid]]}]";
507 }
508
509 svmap.clear();
510 svmap["ismap"] = QVariant::fromValue(value: ismap);
511 svmap["ssmap"] = QVariant::fromValue(value: ssmap);
512 svmap["osmap"] = QVariant::fromValue(value: osmap);
513 svmap["gsmap"] = QVariant::fromValue(value: gsmap);
514 QTest::newRow(dataTag: "sv-map2") << QVariant::fromValue(value: svmap) << "a{sv}"
515 << "[Argument: a{sv} {\"gsmap\" = [Variant: [Argument: a{gs} {[Signature: a{gs}] = \"array of dict_entry of (signature, string)\", [Signature: i] = \"int32\", [Signature: s] = \"string\"}]], \"ismap\" = [Variant: [Argument: a{is} {-47 = \"c\", 1 = \"a\", 2000 = \"b\"}]], \"osmap\" = [Variant: [Argument: a{os} {[ObjectPath: /] = \"root\", [ObjectPath: /bar/baz] = \"bar and baz\", [ObjectPath: /foo] = \"foo\"}]], \"ssmap\" = [Variant: [Argument: a{ss} {\"a\" = \"a\", \"b\" = \"c\", \"c\" = \"b\"}]]}]";
516}
517
518void tst_QDBusMarshall::sendStructs_data()
519{
520 QTest::addColumn<QVariant>(name: "value");
521 QTest::addColumn<QString>(name: "sig");
522 QTest::addColumn<QString>(name: "stringResult");
523
524 QTest::newRow(dataTag: "point") << QVariant(QPoint(1, 2)) << "(ii)" << "[Argument: (ii) 1, 2]";
525 QTest::newRow(dataTag: "pointf") << QVariant(QPointF(1.5, -1.5)) << "(dd)" << "[Argument: (dd) 1.5, -1.5]";
526
527 QTest::newRow(dataTag: "size") << QVariant(QSize(1, 2)) << "(ii)" << "[Argument: (ii) 1, 2]";
528 QTest::newRow(dataTag: "sizef") << QVariant(QSizeF(1.5, 1.5)) << "(dd)" << "[Argument: (dd) 1.5, 1.5]";
529
530 QTest::newRow(dataTag: "rect") << QVariant(QRect(1, 2, 3, 4)) << "(iiii)" << "[Argument: (iiii) 1, 2, 3, 4]";
531 QTest::newRow(dataTag: "rectf") << QVariant(QRectF(0.5, 0.5, 1.5, 1.5)) << "(dddd)" << "[Argument: (dddd) 0.5, 0.5, 1.5, 1.5]";
532
533 QTest::newRow(dataTag: "line") << QVariant(QLine(1, 2, 3, 4)) << "((ii)(ii))"
534 << "[Argument: ((ii)(ii)) [Argument: (ii) 1, 2], [Argument: (ii) 3, 4]]";
535 QTest::newRow(dataTag: "linef") << QVariant(QLineF(0.5, 0.5, 1.5, 1.5)) << "((dd)(dd))"
536 << "[Argument: ((dd)(dd)) [Argument: (dd) 0.5, 0.5], [Argument: (dd) 1.5, 1.5]]";
537
538 QDate date(2006, 6, 18);
539 QTime time(12, 25, 00); // the date I wrote this test on :-)
540 QTest::newRow(dataTag: "date") << QVariant(date) << "(iii)" << "[Argument: (iii) 2006, 6, 18]";
541 QTest::newRow(dataTag: "time") << QVariant(time) << "(iiii)" << "[Argument: (iiii) 12, 25, 0, 0]";
542 QTest::newRow(dataTag: "datetime") << QVariant(QDateTime(date, time)) << "((iii)(iiii)i)"
543 << "[Argument: ((iii)(iiii)i) [Argument: (iii) 2006, 6, 18], [Argument: (iiii) 12, 25, 0, 0], 0]";
544
545 MyStruct ms = { .i: 1, .s: "Hello, World" };
546 QTest::newRow(dataTag: "int-string") << QVariant::fromValue(value: ms) << "(is)" << "[Argument: (is) 1, \"Hello, World\"]";
547
548 MyVariantMapStruct mvms = { .s: "Hello, World", .map: QVariantMap() };
549 QTest::newRow(dataTag: "string-variantmap") << QVariant::fromValue(value: mvms) << "(sa{sv})" << "[Argument: (sa{sv}) \"Hello, World\", [Argument: a{sv} {}]]";
550
551 // use only basic types, otherwise comparison will fail
552 mvms.map["int"] = 42;
553 mvms.map["uint"] = 42u;
554 mvms.map["short"] = QVariant::fromValue<short>(value: -47);
555 mvms.map["bytearray"] = QByteArray("Hello, world");
556 QTest::newRow(dataTag: "string-variantmap2") << QVariant::fromValue(value: mvms) << "(sa{sv})" << "[Argument: (sa{sv}) \"Hello, World\", [Argument: a{sv} {\"bytearray\" = [Variant(QByteArray): {72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100}], \"int\" = [Variant(int): 42], \"short\" = [Variant(short): -47], \"uint\" = [Variant(uint): 42]}]]";
557
558 QList<MyVariantMapStruct> list;
559 QTest::newRow(dataTag: "empty-list-of-string-variantmap") << QVariant::fromValue(value: list) << "a(sa{sv})" << "[Argument: a(sa{sv}) {}]";
560 list << mvms;
561 QTest::newRow(dataTag: "list-of-string-variantmap") << QVariant::fromValue(value: list) << "a(sa{sv})" << "[Argument: a(sa{sv}) {[Argument: (sa{sv}) \"Hello, World\", [Argument: a{sv} {\"bytearray\" = [Variant(QByteArray): {72, 101, 108, 108, 111, 44, 32, 119, 111, 114, 108, 100}], \"int\" = [Variant(int): 42], \"short\" = [Variant(short): -47], \"uint\" = [Variant(uint): 42]}]]}]";
562
563 if (fileDescriptorPassing) {
564 MyFileDescriptorStruct fds;
565 fds.fd = QDBusUnixFileDescriptor(fileDescriptorForTest());
566 QTest::newRow(dataTag: "fdstruct") << QVariant::fromValue(value: fds) << "(h)" << "[Argument: (h) [Unix FD: valid]]";
567
568 QList<MyFileDescriptorStruct> fdlist;
569 QTest::newRow(dataTag: "empty-list-of-fdstruct") << QVariant::fromValue(value: fdlist) << "a(h)" << "[Argument: a(h) {}]";
570
571 fdlist << fds;
572 QTest::newRow(dataTag: "list-of-fdstruct") << QVariant::fromValue(value: fdlist) << "a(h)" << "[Argument: a(h) {[Argument: (h) [Unix FD: valid]]}]";
573 }
574}
575
576void tst_QDBusMarshall::sendComplex_data()
577{
578 QTest::addColumn<QVariant>(name: "value");
579 QTest::addColumn<QString>(name: "sig");
580 QTest::addColumn<QString>(name: "stringResult");
581
582 QList<QDateTime> dtlist;
583 QTest::newRow(dataTag: "empty-datetimelist") << QVariant::fromValue(value: dtlist) << "a((iii)(iiii)i)"
584 << "[Argument: a((iii)(iiii)i) {}]";
585 dtlist << QDateTime();
586 QTest::newRow(dataTag: "list-of-emptydatetime") << QVariant::fromValue(value: dtlist) << "a((iii)(iiii)i)"
587 << "[Argument: a((iii)(iiii)i) {[Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) -1, -1, -1, -1], 0]}]";
588 dtlist << QDateTime(QDate(1977, 9, 13), QTime(0, 0, 0))
589 << QDateTime(QDate(2006, 6, 18), QTime(13, 14, 0));
590 QTest::newRow(dataTag: "datetimelist") << QVariant::fromValue(value: dtlist) << "a((iii)(iiii)i)"
591 << "[Argument: a((iii)(iiii)i) {[Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) -1, -1, -1, -1], 0], [Argument: ((iii)(iiii)i) [Argument: (iii) 1977, 9, 13], [Argument: (iiii) 0, 0, 0, 0], 0], [Argument: ((iii)(iiii)i) [Argument: (iii) 2006, 6, 18], [Argument: (iiii) 13, 14, 0, 0], 0]}]";
592
593 QMap<qlonglong, QDateTime> lldtmap;
594 QTest::newRow(dataTag: "empty-lldtmap") << QVariant::fromValue(value: lldtmap) << "a{x((iii)(iiii)i)}"
595 << "[Argument: a{x((iii)(iiii)i)} {}]";
596 lldtmap[0] = QDateTime();
597 lldtmap[1] = QDateTime(QDate(1970, 1, 1), QTime(0, 0, 1), Qt::UTC);
598 lldtmap[1150629776] = QDateTime(QDate(2006, 6, 18), QTime(11, 22, 56), Qt::UTC);
599 QTest::newRow(dataTag: "lldtmap") << QVariant::fromValue(value: lldtmap) << "a{x((iii)(iiii)i)}"
600 << "[Argument: a{x((iii)(iiii)i)} {0 = [Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) -1, -1, -1, -1], 0], 1 = [Argument: ((iii)(iiii)i) [Argument: (iii) 1970, 1, 1], [Argument: (iiii) 0, 0, 1, 0], 1], 1150629776 = [Argument: ((iii)(iiii)i) [Argument: (iii) 2006, 6, 18], [Argument: (iiii) 11, 22, 56, 0], 1]}]";
601
602
603 QMap<int, QString> ismap;
604 ismap[1] = "a";
605 ismap[2000] = "b";
606 ismap[-47] = "c";
607
608 QMap<QString, QString> ssmap;
609 ssmap["a"] = "a";
610 ssmap["c"] = "b";
611 ssmap["b"] = "c";
612
613 QMap<QDBusSignature, QString> gsmap;
614 gsmap[QDBusSignature("i")] = "int32";
615 gsmap[QDBusSignature("s")] = "string";
616 gsmap[QDBusSignature("a{gs}")] = "array of dict_entry of (signature, string)";
617
618 QVariantMap svmap;
619 svmap["a"] = 1;
620 svmap["c"] = "b";
621 svmap["b"] = QByteArray("c");
622 svmap["d"] = 42U;
623 svmap["e"] = QVariant::fromValue(value: short(-47));
624 svmap["f"] = QVariant::fromValue(value: QDBusVariant(0));
625 svmap["date"] = QDate(1977, 1, 1);
626 svmap["time"] = QTime(8, 58, 0);
627 svmap["datetime"] = QDateTime(QDate(13, 9, 2008), QTime(8, 59, 31));
628 svmap["pointf"] = QPointF(0.5, -0.5);
629 svmap["ismap"] = QVariant::fromValue(value: ismap);
630 svmap["ssmap"] = QVariant::fromValue(value: ssmap);
631 svmap["gsmap"] = QVariant::fromValue(value: gsmap);
632 svmap["dtlist"] = QVariant::fromValue(value: dtlist);
633 svmap["lldtmap"] = QVariant::fromValue(value: lldtmap);
634 QTest::newRow(dataTag: "sv-map") << QVariant::fromValue(value: svmap) << "a{sv}"
635 << "[Argument: a{sv} {\"a\" = [Variant(int): 1], \"b\" = [Variant(QByteArray): {99}], \"c\" = [Variant(QString): \"b\"], \"d\" = [Variant(uint): 42], \"date\" = [Variant: [Argument: (iii) 1977, 1, 1]], \"datetime\" = [Variant: [Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) 8, 59, 31, 0], 0]], \"dtlist\" = [Variant: [Argument: a((iii)(iiii)i) {[Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) -1, -1, -1, -1], 0], [Argument: ((iii)(iiii)i) [Argument: (iii) 1977, 9, 13], [Argument: (iiii) 0, 0, 0, 0], 0], [Argument: ((iii)(iiii)i) [Argument: (iii) 2006, 6, 18], [Argument: (iiii) 13, 14, 0, 0], 0]}]], \"e\" = [Variant(short): -47], \"f\" = [Variant: [Variant(int): 0]], \"gsmap\" = [Variant: [Argument: a{gs} {[Signature: a{gs}] = \"array of dict_entry of (signature, string)\", [Signature: i] = \"int32\", [Signature: s] = \"string\"}]], \"ismap\" = [Variant: [Argument: a{is} {-47 = \"c\", 1 = \"a\", 2000 = \"b\"}]], \"lldtmap\" = [Variant: [Argument: a{x((iii)(iiii)i)} {0 = [Argument: ((iii)(iiii)i) [Argument: (iii) 0, 0, 0], [Argument: (iiii) -1, -1, -1, -1], 0], 1 = [Argument: ((iii)(iiii)i) [Argument: (iii) 1970, 1, 1], [Argument: (iiii) 0, 0, 1, 0], 1], 1150629776 = [Argument: ((iii)(iiii)i) [Argument: (iii) 2006, 6, 18], [Argument: (iiii) 11, 22, 56, 0], 1]}]], \"pointf\" = [Variant: [Argument: (dd) 0.5, -0.5]], \"ssmap\" = [Variant: [Argument: a{ss} {\"a\" = \"a\", \"b\" = \"c\", \"c\" = \"b\"}]], \"time\" = [Variant: [Argument: (iiii) 8, 58, 0, 0]]}]";
636}
637
638void tst_QDBusMarshall::sendArgument_data()
639{
640 QTest::addColumn<QVariant>(name: "value");
641 QTest::addColumn<QString>(name: "sig");
642 QTest::addColumn<int>(name: "classification");
643
644 QDBusArgument();
645 QDBusArgument arg;
646
647 arg = QDBusArgument();
648 arg << true;
649 QTest::newRow(dataTag: "bool") << QVariant::fromValue(value: arg) << "b" << int(QDBusArgument::BasicType);;
650
651 arg = QDBusArgument();
652 arg << false;
653 QTest::newRow(dataTag: "bool2") << QVariant::fromValue(value: arg) << "b" << int(QDBusArgument::BasicType);
654
655 arg = QDBusArgument();
656 arg << uchar(1);
657 QTest::newRow(dataTag: "byte") << QVariant::fromValue(value: arg) << "y" << int(QDBusArgument::BasicType);
658
659 arg = QDBusArgument();
660 arg << short(2);
661 QTest::newRow(dataTag: "int16") << QVariant::fromValue(value: arg) << "n" << int(QDBusArgument::BasicType);
662
663 arg = QDBusArgument();
664 arg << ushort(3);
665 QTest::newRow(dataTag: "uint16") << QVariant::fromValue(value: arg) << "q" << int(QDBusArgument::BasicType);
666
667 arg = QDBusArgument();
668 arg << 1;
669 QTest::newRow(dataTag: "int32") << QVariant::fromValue(value: arg) << "i" << int(QDBusArgument::BasicType);
670
671 arg = QDBusArgument();
672 arg << 2U;
673 QTest::newRow(dataTag: "uint32") << QVariant::fromValue(value: arg) << "u" << int(QDBusArgument::BasicType);
674
675 arg = QDBusArgument();
676 arg << Q_INT64_C(3);
677 QTest::newRow(dataTag: "int64") << QVariant::fromValue(value: arg) << "x" << int(QDBusArgument::BasicType);
678
679 arg = QDBusArgument();
680 arg << Q_UINT64_C(4);
681 QTest::newRow(dataTag: "uint64") << QVariant::fromValue(value: arg) << "t" << int(QDBusArgument::BasicType);
682
683 arg = QDBusArgument();
684 arg << 42.5;
685 QTest::newRow(dataTag: "double") << QVariant::fromValue(value: arg) << "d" << int(QDBusArgument::BasicType);
686
687 arg = QDBusArgument();
688 arg << QLatin1String("ping");
689 QTest::newRow(dataTag: "string") << QVariant::fromValue(value: arg) << "s" << int(QDBusArgument::BasicType);
690
691 arg = QDBusArgument();
692 arg << QDBusObjectPath("/org/kde");
693 QTest::newRow(dataTag: "objectpath") << QVariant::fromValue(value: arg) << "o" << int(QDBusArgument::BasicType);
694
695 arg = QDBusArgument();
696 arg << QDBusSignature("g");
697 QTest::newRow(dataTag: "signature") << QVariant::fromValue(value: arg) << "g" << int(QDBusArgument::BasicType);
698
699 arg = QDBusArgument();
700 arg << QLatin1String("");
701 QTest::newRow(dataTag: "emptystring") << QVariant::fromValue(value: arg) << "s" << int(QDBusArgument::BasicType);
702
703 arg = QDBusArgument();
704 arg << QString();
705 QTest::newRow(dataTag: "nullstring") << QVariant::fromValue(value: arg) << "s" << int(QDBusArgument::BasicType);
706
707 if (fileDescriptorPassing) {
708 arg = QDBusArgument();
709 arg << QDBusUnixFileDescriptor(fileDescriptorForTest());
710 QTest::newRow(dataTag: "filedescriptor") << QVariant::fromValue(value: arg) << "h" << int(QDBusArgument::BasicType);
711 }
712
713 arg = QDBusArgument();
714 arg << QDBusVariant(1);
715 QTest::newRow(dataTag: "variant") << QVariant::fromValue(value: arg) << "v" << int(QDBusArgument::VariantType);
716
717 arg = QDBusArgument();
718 arg << QDBusVariant(QVariant::fromValue(value: QDBusVariant(1)));
719 QTest::newRow(dataTag: "variant-variant") << QVariant::fromValue(value: arg) << "v" << int(QDBusArgument::VariantType);
720
721 arg = QDBusArgument();
722 arg.beginArray(elementMetaTypeId: QVariant::Int);
723 arg << 1 << 2 << 3 << -4;
724 arg.endArray();
725 QTest::newRow(dataTag: "array-of-int") << QVariant::fromValue(value: arg) << "ai" << int(QDBusArgument::ArrayType);
726
727 arg = QDBusArgument();
728 arg.beginMap(keyMetaTypeId: QVariant::Int, valueMetaTypeId: QVariant::UInt);
729 arg.beginMapEntry();
730 arg << 1 << 2U;
731 arg.endMapEntry();
732 arg.beginMapEntry();
733 arg << 3 << 4U;
734 arg.endMapEntry();
735 arg.endMap();
736 QTest::newRow(dataTag: "map") << QVariant::fromValue(value: arg) << "a{iu}" << int(QDBusArgument::MapType);
737
738 arg = QDBusArgument();
739 arg.beginStructure();
740 arg << 1 << 2U << short(-3) << ushort(4) << 5.0 << false;
741 arg.endStructure();
742 QTest::newRow(dataTag: "structure") << QVariant::fromValue(value: arg) << "(iunqdb)" << int(QDBusArgument::StructureType);
743}
744
745void tst_QDBusMarshall::sendBasic()
746{
747 QFETCH(QVariant, value);
748 QFETCH(QString, stringResult);
749
750 QDBusConnection con = QDBusConnection::sessionBus();
751
752 QVERIFY(con.isConnected());
753
754 QDBusMessage msg = QDBusMessage::createMethodCall(destination: serviceName,
755 path: objectPath, interface: interfaceName, method: "ping");
756 msg << value;
757
758 QDBusMessage reply = con.call(message: msg);
759 QVERIFY2(reply.type() == QDBusMessage::ReplyMessage,
760 qPrintable(reply.errorName() + ": " + reply.errorMessage()));
761 //qDebug() << reply;
762
763 QCOMPARE(reply.arguments().count(), msg.arguments().count());
764 QTEST(reply.signature(), "sig");
765 for (int i = 0; i < reply.arguments().count(); ++i) {
766 QVERIFY(compare(reply.arguments().at(i), msg.arguments().at(i)));
767 //printf("\n! %s\n* %s\n", qPrintable(qDBusArgumentToString(reply.arguments().at(i))), qPrintable(stringResult));
768 QCOMPARE(QDBusUtil::argumentToString(reply.arguments().at(i)), stringResult);
769 }
770}
771
772void tst_QDBusMarshall::sendVariant()
773{
774 QFETCH(QVariant, value);
775
776 QDBusConnection con = QDBusConnection::sessionBus();
777
778 QVERIFY(con.isConnected());
779
780 QDBusMessage msg = QDBusMessage::createMethodCall(destination: serviceName,
781 path: objectPath, interface: interfaceName, method: "ping");
782 msg << QVariant::fromValue(value: QDBusVariant(value));
783
784 QDBusMessage reply = con.call(message: msg);
785 // qDebug() << reply;
786
787 QCOMPARE(reply.arguments().count(), msg.arguments().count());
788 QCOMPARE(reply.signature(), QString("v"));
789 for (int i = 0; i < reply.arguments().count(); ++i)
790 QVERIFY(compare(reply.arguments().at(i), msg.arguments().at(i)));
791}
792
793void tst_QDBusMarshall::sendArrays()
794{
795 sendBasic();
796}
797
798void tst_QDBusMarshall::sendArrayOfArrays()
799{
800 sendBasic();
801}
802
803void tst_QDBusMarshall::sendMaps()
804{
805 sendBasic();
806}
807
808void tst_QDBusMarshall::sendStructs()
809{
810 sendBasic();
811}
812
813void tst_QDBusMarshall::sendComplex()
814{
815 sendBasic();
816}
817
818void tst_QDBusMarshall::sendArgument()
819{
820 QFETCH(QVariant, value);
821 QFETCH(QString, sig);
822
823 QDBusConnection con = QDBusConnection::sessionBus();
824
825 QVERIFY(con.isConnected());
826
827 QDBusMessage msg = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath,
828 interface: interfaceName, method: "ping");
829 msg << value;
830
831 QDBusMessage reply = con.call(message: msg);
832
833// QCOMPARE(reply.arguments().count(), msg.arguments().count());
834 QCOMPARE(reply.signature(), sig);
835// for (int i = 0; i < reply.arguments().count(); ++i)
836// QVERIFY(compare(reply.arguments().at(i), msg.arguments().at(i)));
837
838 // do it again inside a STRUCT now
839 QDBusArgument sendArg;
840 sendArg.beginStructure();
841 sendArg.appendVariant(v: value);
842 sendArg.endStructure();
843 msg.setArguments(QVariantList() << QVariant::fromValue(value: sendArg));
844 reply = con.call(message: msg);
845
846 QCOMPARE(reply.signature(), QString("(%1)").arg(sig));
847 QCOMPARE(reply.arguments().at(0).userType(), qMetaTypeId<QDBusArgument>());
848
849 const QDBusArgument arg = qvariant_cast<QDBusArgument>(v: reply.arguments().at(i: 0));
850 QCOMPARE(int(arg.currentType()), int(QDBusArgument::StructureType));
851
852 arg.beginStructure();
853 QVERIFY(!arg.atEnd());
854 QCOMPARE(arg.currentSignature(), sig);
855 QTEST(int(arg.currentType()), "classification");
856
857 QVariant extracted = arg.asVariant();
858 QVERIFY(arg.atEnd());
859
860 arg.endStructure();
861 QVERIFY(arg.atEnd());
862 QCOMPARE(arg.currentType(), QDBusArgument::UnknownType);
863
864 if (value.type() != QVariant::UserType)
865 QCOMPARE(extracted, value);
866}
867
868void tst_QDBusMarshall::sendSignalErrors()
869{
870 QDBusConnection con = QDBusConnection::sessionBus();
871
872 QVERIFY(con.isConnected());
873 QDBusMessage msg = QDBusMessage::createSignal(path: "/foo", interface: "local.interfaceName",
874 name: "signalName");
875 msg << QVariant::fromValue(value: QDBusObjectPath());
876
877 QTest::ignoreMessage(type: QtWarningMsg, message: "QDBusConnection: error: could not send signal to service \"\" path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid object path passed in arguments");
878 QVERIFY(!con.send(msg));
879
880 msg.setArguments(QVariantList());
881 QDBusObjectPath path;
882
883 QTest::ignoreMessage(type: QtWarningMsg, message: "QDBusObjectPath: invalid path \"abc\"");
884 path.setPath("abc");
885 msg << QVariant::fromValue(value: path);
886
887 QTest::ignoreMessage(type: QtWarningMsg, message: "QDBusConnection: error: could not send signal to service \"\" path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid object path passed in arguments");
888 QVERIFY(!con.send(msg));
889
890 QDBusSignature sig;
891 msg.setArguments(QVariantList() << QVariant::fromValue(value: sig));
892 QTest::ignoreMessage(type: QtWarningMsg, message: "QDBusConnection: error: could not send signal to service \"\" path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid signature passed in arguments");
893 QVERIFY(!con.send(msg));
894
895 QTest::ignoreMessage(type: QtWarningMsg, message: "QDBusSignature: invalid signature \"a\"");
896 sig.setSignature("a");
897 msg.setArguments(QVariantList());
898 msg << QVariant::fromValue(value: sig);
899 QTest::ignoreMessage(type: QtWarningMsg, message: "QDBusConnection: error: could not send signal to service \"\" path \"/foo\" interface \"local.interfaceName\" member \"signalName\": Marshalling failed: Invalid signature passed in arguments");
900 QVERIFY(!con.send(msg));
901}
902
903void tst_QDBusMarshall::sendCallErrors_data()
904{
905 QTest::addColumn<QString>(name: "service");
906 QTest::addColumn<QString>(name: "path");
907 QTest::addColumn<QString>(name: "interface");
908 QTest::addColumn<QString>(name: "method");
909 QTest::addColumn<QVariantList>(name: "arguments");
910 QTest::addColumn<QString>(name: "errorName");
911 QTest::addColumn<QString>(name: "errorMsg");
912 QTest::addColumn<QString>(name: "ignoreMsg");
913
914 // this error comes from the bus server
915 QTest::newRow(dataTag: "empty-service") << "" << objectPath << interfaceName << "ping" << QVariantList()
916 << "org.freedesktop.DBus.Error.UnknownMethod"
917 << "Method \"ping\" with signature \"\" on interface \"org.qtproject.autotests.qpong\" doesn't exist\n" << (const char*)0;
918
919 QTest::newRow(dataTag: "invalid-service") << "this isn't valid" << objectPath << interfaceName << "ping" << QVariantList()
920 << "org.qtproject.QtDBus.Error.InvalidService"
921 << "Invalid service name: this isn't valid" << "";
922
923 QTest::newRow(dataTag: "empty-path") << serviceName << "" << interfaceName << "ping" << QVariantList()
924 << "org.qtproject.QtDBus.Error.InvalidObjectPath"
925 << "Object path cannot be empty" << "";
926 QTest::newRow(dataTag: "invalid-path") << serviceName << "//" << interfaceName << "ping" << QVariantList()
927 << "org.qtproject.QtDBus.Error.InvalidObjectPath"
928 << "Invalid object path: //" << "";
929
930 // empty interfaces are valid
931 QTest::newRow(dataTag: "invalid-interface") << serviceName << objectPath << "this isn't valid" << "ping" << QVariantList()
932 << "org.qtproject.QtDBus.Error.InvalidInterface"
933 << "Invalid interface class: this isn't valid" << "";
934
935 QTest::newRow(dataTag: "empty-method") << serviceName << objectPath << interfaceName << "" << QVariantList()
936 << "org.qtproject.QtDBus.Error.InvalidMember"
937 << "method name cannot be empty" << "";
938 QTest::newRow(dataTag: "invalid-method") << serviceName << objectPath << interfaceName << "this isn't valid" << QVariantList()
939 << "org.qtproject.QtDBus.Error.InvalidMember"
940 << "Invalid method name: this isn't valid" << "";
941
942 QTest::newRow(dataTag: "invalid-variant1") << serviceName << objectPath << interfaceName << "ping"
943 << (QVariantList() << QVariant())
944 << "org.freedesktop.DBus.Error.Failed"
945 << "Marshalling failed: Variant containing QVariant::Invalid passed in arguments"
946 << "QDBusMarshaller: cannot add an invalid QVariant";
947 QTest::newRow(dataTag: "invalid-variant1") << serviceName << objectPath << interfaceName << "ping"
948 << (QVariantList() << QVariant::fromValue(value: QDBusVariant()))
949 << "org.freedesktop.DBus.Error.Failed"
950 << "Marshalling failed: Variant containing QVariant::Invalid passed in arguments"
951 << "QDBusMarshaller: cannot add a null QDBusVariant";
952
953 QTest::newRow(dataTag: "builtin-unregistered") << serviceName << objectPath << interfaceName << "ping"
954 << (QVariantList() << QLocale::c())
955 << "org.freedesktop.DBus.Error.Failed"
956 << "Marshalling failed: Unregistered type QLocale passed in arguments"
957 << "QDBusMarshaller: type `QLocale' (18) is not registered with D-BUS. Use qDBusRegisterMetaType to register it";
958
959 // this type is known to the meta type system, but not registered with D-Bus
960 qRegisterMetaType<UnregisteredType>();
961 QTest::newRow(dataTag: "extra-unregistered") << serviceName << objectPath << interfaceName << "ping"
962 << (QVariantList() << QVariant::fromValue(value: UnregisteredType()))
963 << "org.freedesktop.DBus.Error.Failed"
964 << "Marshalling failed: Unregistered type UnregisteredType passed in arguments"
965 << QString("QDBusMarshaller: type `UnregisteredType' (%1) is not registered with D-BUS. Use qDBusRegisterMetaType to register it")
966 .arg(a: qMetaTypeId<UnregisteredType>());
967
968 QTest::newRow(dataTag: "invalid-object-path-arg") << serviceName << objectPath << interfaceName << "ping"
969 << (QVariantList() << QVariant::fromValue(value: QDBusObjectPath()))
970 << "org.freedesktop.DBus.Error.Failed"
971 << "Marshalling failed: Invalid object path passed in arguments"
972 << "";
973
974 QTest::newRow(dataTag: "invalid-signature-arg") << serviceName << objectPath << interfaceName << "ping"
975 << (QVariantList() << QVariant::fromValue(value: QDBusSignature()))
976 << "org.freedesktop.DBus.Error.Failed"
977 << "Marshalling failed: Invalid signature passed in arguments"
978 << "";
979
980 // invalid file descriptor
981 if (fileDescriptorPassing) {
982 QTest::newRow(dataTag: "invalid-file-descriptor") << serviceName << objectPath << interfaceName << "ping"
983 << (QVariantList() << QVariant::fromValue(value: QDBusUnixFileDescriptor(-1)))
984 << "org.freedesktop.DBus.Error.Failed"
985 << "Marshalling failed: Invalid file descriptor passed in arguments"
986 << "";
987 }
988}
989
990void tst_QDBusMarshall::sendCallErrors()
991{
992 QDBusConnection con = QDBusConnection::sessionBus();
993 QVERIFY(con.isConnected());
994
995 QFETCH(QString, service);
996 QFETCH(QString, path);
997 QFETCH(QString, interface);
998 QFETCH(QString, method);
999 QFETCH(QVariantList, arguments);
1000 QFETCH(QString, errorMsg);
1001
1002 QFETCH(QString, ignoreMsg);
1003 if (!ignoreMsg.isEmpty())
1004 QTest::ignoreMessage(type: QtWarningMsg, message: ignoreMsg.toLatin1());
1005 if (!ignoreMsg.isNull())
1006 QTest::ignoreMessage(type: QtWarningMsg,
1007 message: QString("QDBusConnection: error: could not send message to service \"%1\" path \"%2\" interface \"%3\" member \"%4\": %5")
1008 .arg(args&: service, args&: path, args&: interface, args&: method, args&: errorMsg)
1009 .toLatin1());
1010
1011 QDBusMessage msg = QDBusMessage::createMethodCall(destination: service, path, interface, method);
1012 msg.setArguments(arguments);
1013
1014 QDBusMessage reply = con.call(message: msg, mode: QDBus::Block);
1015 QCOMPARE(reply.type(), QDBusMessage::ErrorMessage);
1016 QTEST(reply.errorName(), "errorName");
1017 QCOMPARE(reply.errorMessage(), errorMsg);
1018}
1019
1020// If DBUS_TYPE_UNIX_FD is not defined, it means the current system's D-Bus library is too old for this test
1021void tst_QDBusMarshall::receiveUnknownType_data()
1022{
1023 QTest::addColumn<int>(name: "receivedTypeId");
1024 QTest::newRow(dataTag: "in-call") << qMetaTypeId<void*>();
1025 QTest::newRow(dataTag: "type-variant") << qMetaTypeId<QDBusVariant>();
1026 QTest::newRow(dataTag: "type-array") << qMetaTypeId<QDBusArgument>();
1027 QTest::newRow(dataTag: "type-struct") << qMetaTypeId<QDBusArgument>();
1028 QTest::newRow(dataTag: "type-naked") << qMetaTypeId<void *>();
1029}
1030
1031struct DisconnectRawDBus {
1032 static void cleanup(DBusConnection *connection)
1033 {
1034 if (!connection)
1035 return;
1036 q_dbus_connection_close(connection);
1037 q_dbus_connection_unref(connection);
1038 }
1039};
1040struct UnrefDBusMessage
1041{
1042 static void cleanup(DBusMessage *type)
1043 {
1044 if (!type) return;
1045 q_dbus_message_unref(message: type);
1046 }
1047};
1048struct UnrefDBusPendingCall
1049{
1050 static void cleanup(DBusPendingCall *type)
1051 {
1052 if (!type) return;
1053 q_dbus_pending_call_unref(pending: type);
1054 }
1055};
1056
1057// use these scoped types to avoid memory leaks if QVERIFY or QCOMPARE fails
1058typedef QScopedPointer<DBusConnection, DisconnectRawDBus> ScopedDBusConnection;
1059typedef QScopedPointer<DBusMessage, UnrefDBusMessage> ScopedDBusMessage;
1060typedef QScopedPointer<DBusPendingCall, UnrefDBusPendingCall> ScopedDBusPendingCall;
1061
1062template <typename T> struct SetResetValue
1063{
1064 const T oldValue;
1065 T &value;
1066public:
1067 SetResetValue(T &v, T newValue) : oldValue(v), value(v)
1068 {
1069 value = newValue;
1070 }
1071 ~SetResetValue()
1072 {
1073 value = oldValue;
1074 }
1075};
1076
1077// mostly the same as qdbusintegrator.cpp:connectionCapabilies
1078static bool canSendUnixFd(DBusConnection *connection)
1079{
1080 typedef dbus_bool_t (*can_send_type_t)(DBusConnection *, int);
1081 static can_send_type_t can_send_type = 0;
1082
1083#if defined(QT_LINKED_LIBDBUS)
1084# if DBUS_VERSION-0 >= 0x010400
1085 can_send_type = dbus_connection_can_send_type;
1086# endif
1087#elif QT_CONFIG(library)
1088 // run-time check if the next functions are available
1089 can_send_type = (can_send_type_t)qdbus_resolve_conditionally("dbus_connection_can_send_type");
1090#endif
1091
1092 return can_send_type && can_send_type(connection, DBUS_TYPE_UNIX_FD);
1093}
1094
1095void tst_QDBusMarshall::receiveUnknownType()
1096{
1097 QDBusConnection con = QDBusConnection::sessionBus();
1098 QVERIFY(con.isConnected());
1099
1100 // this needs to be implemented in raw
1101 // open a new connection to the bus daemon
1102 DBusError error;
1103 q_dbus_error_init(error: &error);
1104 ScopedDBusConnection rawcon(q_dbus_bus_get_private(type: DBUS_BUS_SESSION, error: &error));
1105 QVERIFY2(rawcon.data(), error.name);
1106
1107 // check if this bus supports passing file descriptors
1108
1109 if (!canSendUnixFd(connection: rawcon.data()))
1110 QSKIP("Your session bus does not allow sending Unix file descriptors");
1111
1112 // make sure this QDBusConnection won't handle Unix file descriptors
1113 QAtomicInt &capabRef = QDBusConnectionPrivate::d(q: con)->capabilities;
1114 SetResetValue<QAtomicInt> resetter(capabRef,
1115 capabRef & ~QDBusConnection::UnixFileDescriptorPassing);
1116
1117 if (qstrcmp(str1: QTest::currentDataTag(), str2: "in-call") == 0) {
1118 // create a call back to us containing a file descriptor
1119 QDBusMessageSpy spy;
1120 con.registerObject(path: "/spyObject", object: &spy, options: QDBusConnection::ExportAllSlots);
1121 ScopedDBusMessage msg(q_dbus_message_new_method_call(bus_name: con.baseService().toLatin1(), path: "/spyObject", NULL, method: "theSlot"));
1122
1123 int fd = fileno(stdout);
1124 DBusMessageIter iter;
1125 q_dbus_message_iter_init_append(message: msg.data(), iter: &iter);
1126 q_dbus_message_iter_append_basic(iter: &iter, DBUS_TYPE_UNIX_FD, value: &fd);
1127
1128 // try to send to us
1129 DBusPendingCall *pending_ptr;
1130 q_dbus_connection_send_with_reply(connection: rawcon.data(), message: msg.data(), pending_return: &pending_ptr, timeout_milliseconds: 1000);
1131 ScopedDBusPendingCall pending(pending_ptr);
1132
1133 // check that it got sent
1134 while (q_dbus_connection_dispatch(connection: rawcon.data()) == DBUS_DISPATCH_DATA_REMAINS)
1135 ;
1136
1137 // now spin our event loop. We don't catch this call, so let's get the reply
1138 QEventLoop loop;
1139 QTimer::singleShot(msec: 200, receiver: &loop, SLOT(quit()));
1140 loop.exec();
1141
1142 // now try to receive the reply
1143 q_dbus_pending_call_block(pending: pending.data());
1144
1145 // check that the spy received what it was supposed to receive
1146 QCOMPARE(spy.list.size(), 1);
1147 QCOMPARE(spy.list.at(0).arguments().size(), 1);
1148 QFETCH(int, receivedTypeId);
1149 QCOMPARE(spy.list.at(0).arguments().at(0).userType(), receivedTypeId);
1150
1151 msg.reset(other: q_dbus_pending_call_steal_reply(pending: pending.data()));
1152 QVERIFY(msg);
1153 QCOMPARE(q_dbus_message_get_type(msg.data()), DBUS_MESSAGE_TYPE_METHOD_RETURN);
1154 QCOMPARE(q_dbus_message_get_signature(msg.data()), DBUS_TYPE_INT32_AS_STRING);
1155
1156 int retval;
1157 QVERIFY(q_dbus_message_iter_init(msg.data(), &iter));
1158 q_dbus_message_iter_get_basic(iter: &iter, value: &retval);
1159 QCOMPARE(retval, 42);
1160 } else {
1161 // create a signal that we'll emit
1162 static const char signalName[] = "signalName";
1163 static const char interfaceName[] = "local.interface.name";
1164 ScopedDBusMessage msg(q_dbus_message_new_signal(path: "/", interface: interfaceName, name: signalName));
1165 con.connect(service: q_dbus_bus_get_unique_name(connection: rawcon.data()), path: QString(), interface: interfaceName, name: signalName, receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
1166
1167 QDBusMessageSpy spy;
1168 con.connect(service: q_dbus_bus_get_unique_name(connection: rawcon.data()), path: QString(), interface: interfaceName, name: signalName, receiver: &spy, SLOT(theSlot(QDBusMessage)));
1169
1170 DBusMessageIter iter;
1171 q_dbus_message_iter_init_append(message: msg.data(), iter: &iter);
1172 int fd = fileno(stdout);
1173
1174 if (qstrcmp(str1: QTest::currentDataTag(), str2: "type-naked") == 0) {
1175 // send naked
1176 q_dbus_message_iter_append_basic(iter: &iter, DBUS_TYPE_UNIX_FD, value: &fd);
1177 } else {
1178 DBusMessageIter subiter;
1179 if (qstrcmp(str1: QTest::currentDataTag(), str2: "type-variant") == 0)
1180 q_dbus_message_iter_open_container(iter: &iter, DBUS_TYPE_VARIANT, DBUS_TYPE_UNIX_FD_AS_STRING, sub: &subiter);
1181 else if (qstrcmp(str1: QTest::currentDataTag(), str2: "type-array") == 0)
1182 q_dbus_message_iter_open_container(iter: &iter, DBUS_TYPE_ARRAY, DBUS_TYPE_UNIX_FD_AS_STRING, sub: &subiter);
1183 else if (qstrcmp(str1: QTest::currentDataTag(), str2: "type-struct") == 0)
1184 q_dbus_message_iter_open_container(iter: &iter, DBUS_TYPE_STRUCT, contained_signature: 0, sub: &subiter);
1185 q_dbus_message_iter_append_basic(iter: &subiter, DBUS_TYPE_UNIX_FD, value: &fd);
1186 q_dbus_message_iter_close_container(iter: &iter, sub: &subiter);
1187 }
1188
1189 // send it
1190 q_dbus_connection_send(connection: rawcon.data(), message: msg.data(), client_serial: 0);
1191
1192 // check that it got sent
1193 while (q_dbus_connection_dispatch(connection: rawcon.data()) == DBUS_DISPATCH_DATA_REMAINS)
1194 ;
1195
1196 // now let's see what happens
1197 QTestEventLoop::instance().enterLoop(secs: 1);
1198 QVERIFY(!QTestEventLoop::instance().timeout());
1199 QCOMPARE(spy.list.size(), 1);
1200 QCOMPARE(spy.list.at(0).arguments().count(), 1);
1201 QFETCH(int, receivedTypeId);
1202 //qDebug() << spy.list.at(0).arguments().at(0).typeName();
1203 QCOMPARE(spy.list.at(0).arguments().at(0).userType(), receivedTypeId);
1204 }
1205}
1206
1207void tst_QDBusMarshall::demarshallPrimitives_data()
1208{
1209 addBasicTypesColumns();
1210
1211 // Primitive types, excluding strings and FD
1212 basicNumericTypes_data();
1213}
1214
1215template<class T>
1216QVariant demarshallPrimitiveAs(const QDBusArgument& dbusArg)
1217{
1218 T val;
1219 dbusArg >> val;
1220 return QVariant::fromValue(val);
1221}
1222
1223QVariant demarshallPrimitiveAs(int typeIndex, const QDBusArgument& dbusArg)
1224{
1225 switch (typeIndex) {
1226 case 0:
1227 return demarshallPrimitiveAs<uchar>(dbusArg);
1228 case 1:
1229 return demarshallPrimitiveAs<bool>(dbusArg);
1230 case 2:
1231 return demarshallPrimitiveAs<short>(dbusArg);
1232 case 3:
1233 return demarshallPrimitiveAs<ushort>(dbusArg);
1234 case 4:
1235 return demarshallPrimitiveAs<int>(dbusArg);
1236 case 5:
1237 return demarshallPrimitiveAs<uint>(dbusArg);
1238 case 6:
1239 return demarshallPrimitiveAs<qlonglong>(dbusArg);
1240 case 7:
1241 return demarshallPrimitiveAs<qulonglong>(dbusArg);
1242 case 8:
1243 return demarshallPrimitiveAs<double>(dbusArg);
1244 default:
1245 return QVariant();
1246 }
1247}
1248
1249void tst_QDBusMarshall::demarshallPrimitives()
1250{
1251 QFETCH(QVariant, value);
1252 QFETCH(QString, sig);
1253
1254 QDBusConnection con = QDBusConnection::sessionBus();
1255
1256 QVERIFY(con.isConnected());
1257
1258 // Demarshall each test data value to all primitive types to test
1259 // demarshalling to the wrong type does not cause a crash
1260 for (int typeIndex = 0; true; ++typeIndex) {
1261 QDBusMessage msg = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath,
1262 interface: interfaceName, method: "ping");
1263 QDBusArgument sendArg;
1264 sendArg.beginStructure();
1265 sendArg.appendVariant(v: value);
1266 sendArg.endStructure();
1267 msg.setArguments(QVariantList() << QVariant::fromValue(value: sendArg));
1268 QDBusMessage reply = con.call(message: msg);
1269
1270 const QDBusArgument receiveArg = qvariant_cast<QDBusArgument>(v: reply.arguments().at(i: 0));
1271 receiveArg.beginStructure();
1272 QCOMPARE(receiveArg.currentSignature(), sig);
1273
1274 const QVariant receiveValue = demarshallPrimitiveAs(typeIndex, dbusArg: receiveArg);
1275 if (receiveValue.type() == value.type()) {
1276 // Value type is the same, compare the values
1277 QCOMPARE(receiveValue, value);
1278 QVERIFY(receiveArg.atEnd());
1279 }
1280
1281 receiveArg.endStructure();
1282 QVERIFY(receiveArg.atEnd());
1283
1284 if (!receiveValue.isValid())
1285 break;
1286 }
1287}
1288
1289void tst_QDBusMarshall::demarshallStrings_data()
1290{
1291 QTest::addColumn<QVariant>(name: "value");
1292 QTest::addColumn<char>(name: "targetSig");
1293 QTest::addColumn<QVariant>(name: "expectedValue");
1294
1295 // All primitive types demarshall to null string types
1296 typedef QPair<QVariant, char> ValSigPair;
1297 const QList<ValSigPair> nullStringTypes
1298 = QList<ValSigPair>()
1299 << ValSigPair(QVariant::fromValue(value: QString()), 's')
1300 << ValSigPair(QVariant::fromValue(value: QDBusObjectPath()), 'o')
1301 << ValSigPair(QVariant::fromValue(value: QDBusSignature()), 'g');
1302 foreach (ValSigPair valSigPair, nullStringTypes) {
1303 QTest::newRow(dataTag: "bool(false)") << QVariant(false) << valSigPair.second << valSigPair.first;
1304 QTest::newRow(dataTag: "bool(true)") << QVariant(true) << valSigPair.second << valSigPair.first;
1305 QTest::newRow(dataTag: "byte") << QVariant::fromValue(value: uchar(1)) << valSigPair.second << valSigPair.first;
1306 QTest::newRow(dataTag: "int16") << QVariant::fromValue(value: short(2)) << valSigPair.second << valSigPair.first;
1307 QTest::newRow(dataTag: "uint16") << QVariant::fromValue(value: ushort(3)) << valSigPair.second << valSigPair.first;
1308 QTest::newRow(dataTag: "int") << QVariant(1) << valSigPair.second << valSigPair.first;
1309 QTest::newRow(dataTag: "uint") << QVariant(2U) << valSigPair.second << valSigPair.first;
1310 QTest::newRow(dataTag: "int64") << QVariant(Q_INT64_C(3)) << valSigPair.second << valSigPair.first;
1311 QTest::newRow(dataTag: "uint64") << QVariant(Q_UINT64_C(4)) << valSigPair.second << valSigPair.first;
1312 QTest::newRow(dataTag: "double") << QVariant(42.5) << valSigPair.second << valSigPair.first;
1313 }
1314
1315 // String types should demarshall to each other. This is a regression test
1316 // to check released functionality is maintained even after checks have
1317 // been added to string demarshalling
1318 QTest::newRow(dataTag: "empty string->invalid objectpath") << QVariant("")
1319 << 'o' << QVariant::fromValue(value: QDBusObjectPath());
1320 QTest::newRow(dataTag: "null string->invalid objectpath") << QVariant(QString())
1321 << 'o' << QVariant::fromValue(value: QDBusObjectPath());
1322 QTest::newRow(dataTag: "string->invalid objectpath") << QVariant("invalid objectpath")
1323 << 'o' << QVariant::fromValue(value: QDBusObjectPath());
1324 QTest::newRow(dataTag: "string->valid objectpath") << QVariant("/org/kde")
1325 << 'o' << QVariant::fromValue(value: QDBusObjectPath("/org/kde"));
1326
1327 QTest::newRow(dataTag: "empty string->invalid signature") << QVariant("")
1328 << 'g' << QVariant::fromValue(value: QDBusSignature());
1329 QTest::newRow(dataTag: "null string->invalid signature") << QVariant(QString())
1330 << 'g' << QVariant::fromValue(value: QDBusSignature());
1331 QTest::newRow(dataTag: "string->invalid signature") << QVariant("_invalid signature")
1332 << 'g' << QVariant::fromValue(value: QDBusSignature());
1333 QTest::newRow(dataTag: "string->valid signature") << QVariant("s")
1334 << 'g' << QVariant::fromValue(value: QDBusSignature("s"));
1335
1336 QTest::newRow(dataTag: "objectpath->string") << QVariant::fromValue(value: QDBusObjectPath("/org/kde"))
1337 << 's' << QVariant::fromValue(value: QString("/org/kde"));
1338 QTest::newRow(dataTag: "objectpath->invalid signature") << QVariant::fromValue(value: QDBusObjectPath("/org/kde"))
1339 << 'g' << QVariant::fromValue(value: QDBusSignature());
1340
1341 QTest::newRow(dataTag: "signature->string") << QVariant::fromValue(value: QDBusSignature("s"))
1342 << 's' << QVariant::fromValue(value: QString("s"));
1343 QTest::newRow(dataTag: "signature->invalid objectpath") << QVariant::fromValue(value: QDBusSignature("s"))
1344 << 'o' << QVariant::fromValue(value: QDBusObjectPath());
1345}
1346
1347QVariant demarshallAsString(const QDBusArgument& dbusArg, char targetSig)
1348{
1349 switch (targetSig) {
1350 case 's': {
1351 QString s;
1352 dbusArg >> s;
1353 return s;
1354 }
1355 case 'o': {
1356 QDBusObjectPath op;
1357 dbusArg >> op;
1358 return QVariant::fromValue(value: op);
1359 }
1360 case 'g' : {
1361 QDBusSignature sig;
1362 dbusArg >> sig;
1363 return QVariant::fromValue(value: sig);
1364 }
1365 default: {
1366 return QVariant();
1367 }
1368 }
1369}
1370
1371void tst_QDBusMarshall::demarshallStrings()
1372{
1373 QFETCH(QVariant, value);
1374 QFETCH(char, targetSig);
1375 QFETCH(QVariant, expectedValue);
1376
1377 QDBusConnection con = QDBusConnection::sessionBus();
1378
1379 QVERIFY(con.isConnected());
1380
1381 QDBusMessage msg = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath,
1382 interface: interfaceName, method: "ping");
1383 QDBusArgument sendArg;
1384 sendArg.beginStructure();
1385 sendArg.appendVariant(v: value);
1386 sendArg.endStructure();
1387 msg.setArguments(QVariantList() << QVariant::fromValue(value: sendArg));
1388 QDBusMessage reply = con.call(message: msg);
1389
1390 const QDBusArgument receiveArg = qvariant_cast<QDBusArgument>(v: reply.arguments().at(i: 0));
1391 receiveArg.beginStructure();
1392
1393 QVariant receiveValue = demarshallAsString(dbusArg: receiveArg, targetSig);
1394 QVERIFY2(receiveValue.isValid(), "Invalid targetSig in demarshallStrings_data()");
1395 QVERIFY(compare(receiveValue, expectedValue));
1396
1397 receiveArg.endStructure();
1398 QVERIFY(receiveArg.atEnd());
1399}
1400
1401void tst_QDBusMarshall::demarshallInvalidStringList_data()
1402{
1403 addBasicTypesColumns();
1404
1405 // None of the basic types should demarshall to a string list
1406 basicNumericTypes_data();
1407 basicStringTypes_data();
1408
1409 // Arrays of non-string type should not demarshall to a string list
1410 QList<bool> bools;
1411 QTest::newRow(dataTag: "emptyboollist") << QVariant::fromValue(value: bools);
1412 bools << false << true << false;
1413 QTest::newRow(dataTag: "boollist") << QVariant::fromValue(value: bools);
1414
1415 // Structures should not demarshall to a QByteArray
1416 QTest::newRow(dataTag: "struct of strings")
1417 << QVariant::fromValue(value: QVariantList() << QString("foo") << QString("bar"));
1418 QTest::newRow(dataTag: "struct of mixed types")
1419 << QVariant::fromValue(value: QVariantList() << QString("foo") << int(42) << double(3.14));
1420}
1421
1422void tst_QDBusMarshall::demarshallInvalidStringList()
1423{
1424 QFETCH(QVariant, value);
1425
1426 QDBusConnection con = QDBusConnection::sessionBus();
1427
1428 QVERIFY(con.isConnected());
1429
1430 QDBusMessage msg = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath,
1431 interface: interfaceName, method: "ping");
1432 QDBusArgument sendArg;
1433 sendArg.beginStructure();
1434 sendArg.appendVariant(v: value);
1435 sendArg.endStructure();
1436 msg.setArguments(QVariantList() << QVariant::fromValue(value: sendArg));
1437 QDBusMessage reply = con.call(message: msg);
1438
1439 const QDBusArgument receiveArg = qvariant_cast<QDBusArgument>(v: reply.arguments().at(i: 0));
1440 receiveArg.beginStructure();
1441
1442 QStringList receiveValue;
1443 receiveArg >> receiveValue;
1444 QCOMPARE(receiveValue, QStringList());
1445
1446 receiveArg.endStructure();
1447 QVERIFY(receiveArg.atEnd());
1448}
1449
1450void tst_QDBusMarshall::demarshallInvalidByteArray_data()
1451{
1452 addBasicTypesColumns();
1453
1454 // None of the basic types should demarshall to a QByteArray
1455 basicNumericTypes_data();
1456 basicStringTypes_data();
1457
1458 // Arrays of other types than byte should not demarshall to a QByteArray
1459 QList<bool> bools;
1460 QTest::newRow(dataTag: "empty array of bool") << QVariant::fromValue(value: bools);
1461 bools << true << false << true;
1462 QTest::newRow(dataTag: "non-empty array of bool") << QVariant::fromValue(value: bools);
1463
1464 // Structures should not demarshall to a QByteArray
1465 QTest::newRow(dataTag: "struct of bytes")
1466 << QVariant::fromValue(value: QVariantList() << uchar(1) << uchar(2));
1467
1468 QTest::newRow(dataTag: "struct of mixed types")
1469 << QVariant::fromValue(value: QVariantList() << int(42) << QString("foo") << double(3.14));
1470}
1471
1472void tst_QDBusMarshall::demarshallInvalidByteArray()
1473{
1474 QFETCH(QVariant, value);
1475
1476 QDBusConnection con = QDBusConnection::sessionBus();
1477
1478 QVERIFY(con.isConnected());
1479
1480 QDBusMessage msg = QDBusMessage::createMethodCall(destination: serviceName, path: objectPath,
1481 interface: interfaceName, method: "ping");
1482 QDBusArgument sendArg;
1483 sendArg.beginStructure();
1484 sendArg.appendVariant(v: value);
1485 sendArg.endStructure();
1486 msg.setArguments(QVariantList() << QVariant::fromValue(value: sendArg));
1487 QDBusMessage reply = con.call(message: msg);
1488
1489 const QDBusArgument receiveArg = qvariant_cast<QDBusArgument>(v: reply.arguments().at(i: 0));
1490 receiveArg.beginStructure();
1491
1492 QByteArray receiveValue;
1493 receiveArg >> receiveValue;
1494 QCOMPARE(receiveValue, QByteArray());
1495
1496 receiveArg.endStructure();
1497 QVERIFY(receiveArg.atEnd());
1498}
1499
1500QTEST_MAIN(tst_QDBusMarshall)
1501#include "tst_qdbusmarshall.moc"
1502

source code of qtbase/tests/auto/dbus/qdbusmarshall/tst_qdbusmarshall.cpp