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 | |
29 | #include <QtTest/QtTest> |
30 | |
31 | #include <qobject.h> |
32 | #include <qmetaobject.h> |
33 | #include <qabstractproxymodel.h> |
34 | #ifdef QT_BUILD_INTERNAL |
35 | #undef QT_BUILD_INTERNAL // Verdigris don't test the internals |
36 | #endif |
37 | |
38 | #include <wobjectimpl.h> |
39 | |
40 | Q_DECLARE_METATYPE(const QMetaObject *) |
41 | |
42 | W_REGISTER_ARGTYPE(QList<QString>) |
43 | |
44 | struct MyStruct |
45 | { |
46 | int i; |
47 | }; |
48 | |
49 | class MyGadget |
50 | { |
51 | W_GADGET(MyGadget) |
52 | public: |
53 | MyGadget() {} |
54 | W_CONSTRUCTOR() |
55 | }; |
56 | |
57 | W_GADGET_IMPL(MyGadget) |
58 | |
59 | namespace MyNamespace { |
60 | // Used in tst_QMetaObject::checkScope |
61 | class MyClass : public QObject |
62 | { |
63 | W_OBJECT(MyClass) |
64 | |
65 | public: |
66 | enum MyEnum { |
67 | MyEnum1, |
68 | MyEnum2, |
69 | MyEnum3 |
70 | }; |
71 | enum class MyScopedEnum { |
72 | Enum1, |
73 | Enum2, |
74 | Enum3 |
75 | }; |
76 | enum MyAnotherEnum { |
77 | MyAnotherEnum1 = 1, |
78 | MyAnotherEnum2 = 2, |
79 | MyAnotherEnum3 = -1 |
80 | }; |
81 | enum MyFlag { |
82 | MyFlag1 = 0x01, |
83 | MyFlag2 = 0x02, |
84 | MyFlag3 = 0x04 |
85 | }; |
86 | enum class MyScopedFlag { |
87 | MyFlag1 = 0x10, |
88 | MyFlag2 = 0x20, |
89 | MyFlag3 = 0x40 |
90 | }; |
91 | W_DECLARE_FLAGS(MyFlags, MyFlag) |
92 | W_DECLARE_FLAGS(MyScopedFlags, MyScopedFlag) |
93 | |
94 | MyEnum myEnum() const { return m_enum; } |
95 | void setMyEnum(MyEnum val) { m_enum = val; } |
96 | |
97 | MyFlags myFlags() const { return m_flags; } |
98 | void setMyFlags(MyFlags val) { m_flags = val; } |
99 | |
100 | MyClass(QObject *parent = 0) |
101 | : QObject(parent), |
102 | m_enum(MyEnum1), |
103 | m_flags(MyFlag1|MyFlag2) |
104 | { } |
105 | private: |
106 | W_ENUM(MyEnum, MyEnum1, MyEnum2, MyEnum3) |
107 | W_ENUM(MyScopedEnum, MyScopedEnum::Enum1, MyScopedEnum::Enum2, MyScopedEnum::Enum3) |
108 | W_ENUM(MyAnotherEnum,MyAnotherEnum1,MyAnotherEnum2,MyAnotherEnum3) |
109 | W_FLAG(MyFlags,MyFlag1,MyFlag2,MyFlag3) |
110 | W_FLAG(MyScopedFlags, MyScopedFlag::MyFlag1, MyScopedFlag::MyFlag2, MyScopedFlag::MyFlag3) |
111 | |
112 | |
113 | MyEnum m_enum; |
114 | MyFlags m_flags; |
115 | |
116 | W_PROPERTY(MyEnum, myEnum READ myEnum WRITE setMyEnum) |
117 | W_PROPERTY(MyFlags, myFlags READ myFlags WRITE setMyFlags) |
118 | |
119 | |
120 | }; |
121 | Q_DECLARE_OPERATORS_FOR_FLAGS(MyClass::MyFlags) |
122 | |
123 | |
124 | // test the old Q_ENUMS macro |
125 | class MyClass2 : public QObject |
126 | { |
127 | W_OBJECT(MyClass2) |
128 | |
129 | public: |
130 | enum MyEnum { |
131 | MyEnum1, |
132 | MyEnum2, |
133 | MyEnum3 |
134 | }; |
135 | enum MyAnotherEnum { |
136 | MyAnotherEnum1 = 1, |
137 | MyAnotherEnum2 = 2, |
138 | MyAnotherEnum3 = -1 |
139 | }; |
140 | enum MyFlag { |
141 | MyFlag1 = 0x01, |
142 | MyFlag2 = 0x02, |
143 | MyFlag3 = 0x04 |
144 | }; |
145 | Q_DECLARE_FLAGS(MyFlags, MyFlag) |
146 | |
147 | MyEnum myEnum() const { return m_enum; } |
148 | void setMyEnum(MyEnum val) { m_enum = val; } |
149 | |
150 | MyFlags myFlags() const { return m_flags; } |
151 | void setMyFlags(MyFlags val) { m_flags = val; } |
152 | |
153 | MyClass2(QObject *parent = 0) |
154 | : QObject(parent), |
155 | m_enum(MyEnum1), |
156 | m_flags(MyFlag1|MyFlag2) |
157 | { } |
158 | private: |
159 | |
160 | W_ENUM(MyEnum, MyEnum1, MyEnum2, MyEnum3) |
161 | W_ENUM(MyAnotherEnum,MyAnotherEnum1,MyAnotherEnum2,MyAnotherEnum3) |
162 | W_FLAG(MyFlags,MyFlag1,MyFlag2,MyFlag3) |
163 | |
164 | MyEnum m_enum; |
165 | MyFlags m_flags; |
166 | |
167 | W_PROPERTY(MyEnum, myEnum READ myEnum WRITE setMyEnum) |
168 | W_PROPERTY(MyFlags, myFlags READ myFlags WRITE setMyFlags) |
169 | |
170 | }; |
171 | |
172 | // Test inherits |
173 | class MyClassSubclass : public MyClass |
174 | { |
175 | W_OBJECT(MyClassSubclass) |
176 | }; |
177 | |
178 | class MyClassSubclass2 : public MyClass2 |
179 | { |
180 | W_OBJECT(MyClassSubclass2) |
181 | }; |
182 | |
183 | class MyClass2Subclass : public MyClass |
184 | { |
185 | W_OBJECT(MyClass2Subclass) |
186 | }; |
187 | |
188 | #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) |
189 | class ClassWithSetterGetterSignals : public QObject |
190 | { |
191 | W_OBJECT(ClassWithSetterGetterSignals) |
192 | |
193 | public: |
194 | int value1() const { return m_value1; } |
195 | void setValue1(int v) { |
196 | if (v != m_value1) { |
197 | m_value1 = v; |
198 | Q_EMIT value1Changed(); |
199 | } |
200 | } |
201 | |
202 | int value2() const { return m_value2; } |
203 | void setValue2(int v) { |
204 | if (v != m_value2) { |
205 | m_value2 = v; |
206 | Q_EMIT value2Changed(); |
207 | } |
208 | } |
209 | |
210 | Q_SIGNALS: |
211 | void value1Changed() W_SIGNAL(value1Changed) |
212 | void value2Changed() W_SIGNAL(value2Changed) |
213 | |
214 | private: |
215 | int m_value1 = 0; |
216 | int m_value2 = 0; |
217 | }; |
218 | |
219 | class ClassWithSetterGetterSignalsAddsProperties : public ClassWithSetterGetterSignals |
220 | { |
221 | W_OBJECT(ClassWithSetterGetterSignalsAddsProperties) |
222 | W_PROPERTY(int, value1 READ value1 WRITE setValue1 NOTIFY value1Changed) |
223 | W_PROPERTY(int, value2 READ value2 WRITE setValue2 NOTIFY value2Changed) |
224 | }; |
225 | |
226 | class ClassWithChangedSignal : public QObject |
227 | { |
228 | W_OBJECT(ClassWithChangedSignal) |
229 | |
230 | public: |
231 | int value1() const { return m_value1; } |
232 | void setValue1(int v) { |
233 | if (v != m_value1) { |
234 | m_value1 = v; |
235 | Q_EMIT propertiesChanged(); |
236 | } |
237 | } |
238 | |
239 | void thisIsNotASignal() { } |
240 | |
241 | Q_SIGNALS: |
242 | void propertiesChanged() W_SIGNAL(propertiesChanged) |
243 | |
244 | private: |
245 | int m_value1 = 0; |
246 | }; |
247 | |
248 | class ClassWithChangedSignalNewValue : public ClassWithChangedSignal |
249 | { |
250 | W_OBJECT(ClassWithChangedSignalNewValue) |
251 | |
252 | |
253 | private: |
254 | int m_value2 = 0; |
255 | int m_value3 = 0; |
256 | |
257 | W_PROPERTY(int, value2 MEMBER m_value2 NOTIFY propertiesChanged) |
258 | #if 0 // With verdigris, this is a compilation error when the NOTIFY signal is not a signal |
259 | W_PROPERTY(int, value3 MEMBER m_value3 NOTIFY thisIsNotASignal) |
260 | #endif |
261 | }; |
262 | #endif |
263 | } |
264 | W_OBJECT_IMPL(MyNamespace::MyClass) |
265 | W_OBJECT_IMPL(MyNamespace::MyClass2) |
266 | W_OBJECT_IMPL(MyNamespace::MyClassSubclass) |
267 | W_OBJECT_IMPL(MyNamespace::MyClassSubclass2) |
268 | W_OBJECT_IMPL(MyNamespace::MyClass2Subclass) |
269 | #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) |
270 | W_OBJECT_IMPL(MyNamespace::ClassWithSetterGetterSignals) |
271 | W_OBJECT_IMPL(MyNamespace::ClassWithSetterGetterSignalsAddsProperties) |
272 | W_OBJECT_IMPL(MyNamespace::ClassWithChangedSignal) |
273 | W_OBJECT_IMPL(MyNamespace::ClassWithChangedSignalNewValue) |
274 | #endif |
275 | |
276 | class tst_QMetaObject : public QObject |
277 | { |
278 | W_OBJECT(tst_QMetaObject) |
279 | |
280 | public: |
281 | enum EnumType { EnumType1 }; |
282 | W_ENUM(EnumType,EnumType1); |
283 | |
284 | void setValue(EnumType) {} |
285 | EnumType getValue() const { return EnumType1; } |
286 | |
287 | void set_value(EnumType) {} |
288 | EnumType get_value() const { return EnumType1; } |
289 | |
290 | void setVal3(MyStruct) {} |
291 | MyStruct val3() const { MyStruct s = {42}; return s; } |
292 | |
293 | void setVal4(const QList<QVariant> &list) { value4 = list; } |
294 | QList<QVariant> val4() const { return value4; } |
295 | |
296 | void setVal5(const QVariantList &list) { value5 = list; } |
297 | QVariantList val5() const { return value5; } |
298 | |
299 | int value6() const { return 1; } |
300 | |
301 | void setVal7(MyStruct) {} |
302 | MyStruct value7() const { MyStruct s = {42}; return s; } |
303 | |
304 | int value8() const { return 1; } |
305 | |
306 | int value9() const { return 1; } |
307 | |
308 | int value10() const { return 1; } |
309 | |
310 | QList<QVariant> value4; |
311 | QVariantList value5; |
312 | |
313 | private slots: |
314 | #define DECLARE_TEST(NAME) void NAME(); W_SLOT(NAME) |
315 | DECLARE_TEST(connectSlotsByName) |
316 | DECLARE_TEST(invokeMetaMember) |
317 | DECLARE_TEST(invokePointer) |
318 | DECLARE_TEST(invokeQueuedMetaMember) |
319 | DECLARE_TEST(invokeQueuedPointer) |
320 | DECLARE_TEST(invokeBlockingQueuedMetaMember) |
321 | DECLARE_TEST(invokeBlockingQueuedPointer) |
322 | DECLARE_TEST(invokeCustomTypes) |
323 | DECLARE_TEST(invokeMetaConstructor) |
324 | DECLARE_TEST(invokeTypedefTypes) |
325 | DECLARE_TEST(invokeException) |
326 | DECLARE_TEST(invokeQueuedAutoRegister) |
327 | DECLARE_TEST(qtMetaObjectInheritance) |
328 | DECLARE_TEST(normalizedSignature_data) |
329 | DECLARE_TEST(normalizedSignature) |
330 | DECLARE_TEST(normalizedType_data) |
331 | DECLARE_TEST(normalizedType) |
332 | DECLARE_TEST(customPropertyType) |
333 | DECLARE_TEST(checkScope_data) |
334 | DECLARE_TEST(checkScope) |
335 | DECLARE_TEST(propertyNotify) |
336 | DECLARE_TEST(propertyConstant) |
337 | DECLARE_TEST(propertyFinal) |
338 | |
339 | DECLARE_TEST(stdSet) |
340 | DECLARE_TEST(classInfo) |
341 | |
342 | DECLARE_TEST(metaMethod) |
343 | |
344 | DECLARE_TEST(indexOfMethod_data) |
345 | DECLARE_TEST(indexOfMethod) |
346 | |
347 | DECLARE_TEST(indexOfMethodPMF) |
348 | |
349 | #ifdef QT_BUILD_INTERNAL |
350 | DECLARE_TEST(signalOffset_data) |
351 | DECLARE_TEST(signalOffset) |
352 | DECLARE_TEST(signalCount_data) |
353 | DECLARE_TEST(signalCount) |
354 | DECLARE_TEST(signal_data) |
355 | DECLARE_TEST(signal) |
356 | DECLARE_TEST(signalIndex_data) |
357 | DECLARE_TEST(signalIndex) |
358 | #endif |
359 | DECLARE_TEST(enumDebugStream_data) |
360 | DECLARE_TEST(enumDebugStream) |
361 | |
362 | DECLARE_TEST(inherits_data) |
363 | DECLARE_TEST(inherits) |
364 | |
365 | DECLARE_TEST(notifySignalsInParentClass) |
366 | #undef DECLARE_TEST |
367 | |
368 | signals: |
369 | void value6Changed() |
370 | W_SIGNAL(value6Changed) |
371 | void value7Changed(const QString &_) |
372 | W_SIGNAL(value7Changed,_) |
373 | |
374 | |
375 | W_PROPERTY(EnumType, value WRITE setValue READ getValue) |
376 | W_PROPERTY(EnumType, value2 WRITE set_value READ get_value) |
377 | W_PROPERTY(MyStruct, value3 WRITE setVal3 READ val3) |
378 | W_PROPERTY(QList<QVariant>, value4 WRITE setVal4 READ val4) |
379 | W_PROPERTY(QVariantList, value5 WRITE setVal5 READ val5) |
380 | W_PROPERTY(int, value6 READ value6 NOTIFY value6Changed) |
381 | W_PROPERTY(MyStruct, value7 READ value7 WRITE setVal7 NOTIFY value7Changed) |
382 | W_PROPERTY(int, value8 READ value8) |
383 | W_PROPERTY(int, value9 READ value9 CONSTANT) |
384 | W_PROPERTY(int, value10 READ value10 FINAL) |
385 | |
386 | }; |
387 | |
388 | W_OBJECT_IMPL(tst_QMetaObject) |
389 | |
390 | |
391 | void tst_QMetaObject::stdSet() |
392 | { |
393 | QSKIP("Not supported by W_PROPERTY" ); |
394 | |
395 | const QMetaObject *mo = metaObject(); |
396 | |
397 | QMetaProperty prop = mo->property(mo->indexOfProperty("value" )); |
398 | QVERIFY(prop.isValid()); |
399 | QVERIFY(prop.hasStdCppSet()); |
400 | |
401 | prop = mo->property(mo->indexOfProperty("value2" )); |
402 | QVERIFY(prop.isValid()); |
403 | QVERIFY(!prop.hasStdCppSet()); |
404 | } |
405 | |
406 | class CTestObject: public QObject |
407 | { |
408 | W_OBJECT(CTestObject) |
409 | |
410 | public: |
411 | CTestObject(): QObject(), invokeCount1(0), invokeCount2(0) |
412 | { |
413 | } |
414 | |
415 | void fire(const QString &name) |
416 | { |
417 | child = new QObject(this); |
418 | child->setObjectName(name); |
419 | QMetaObject::connectSlotsByName(this); |
420 | delete child; child = 0; |
421 | } |
422 | |
423 | int invokeCount1; |
424 | int invokeCount2; |
425 | QObject *child; |
426 | |
427 | public slots: |
428 | void on_child1_destroyed(QObject *obj = 0) |
429 | { |
430 | ++invokeCount1; |
431 | if (!obj || obj != child) |
432 | qWarning() << "on_child1_destroyed invoked with wrong child object" ; |
433 | } |
434 | W_SLOT(on_child1_destroyed) |
435 | void on_child2_destroyed() { ++invokeCount2; } |
436 | W_SLOT(on_child2_destroyed) |
437 | }; |
438 | |
439 | W_OBJECT_IMPL(CTestObject) |
440 | |
441 | |
442 | class CTestObjectOverloads: public QObject |
443 | { |
444 | W_OBJECT(CTestObjectOverloads) |
445 | |
446 | public: |
447 | CTestObjectOverloads(): invokeCount1(0), invokeCount2(0) {} |
448 | |
449 | int invokeCount1; |
450 | int invokeCount2; |
451 | QObject *child; |
452 | |
453 | void fire(const QString &name) |
454 | { |
455 | child = new QObject(this); |
456 | child->setObjectName(name); |
457 | QMetaObject::connectSlotsByName(this); |
458 | delete child; child = 0; |
459 | } |
460 | |
461 | private slots: |
462 | void on_child1_destroyed(QObject *obj) |
463 | { |
464 | ++invokeCount1; |
465 | if (!obj || obj != child) |
466 | qWarning() << "on_child1_destroyed invoked with wrong child object" ; |
467 | } |
468 | W_SLOT(on_child1_destroyed,(QObject*)) |
469 | void on_child1_destroyed() { ++invokeCount2; } |
470 | W_SLOT(on_child1_destroyed,()) |
471 | }; |
472 | |
473 | W_OBJECT_IMPL(CTestObjectOverloads) |
474 | |
475 | #define FUNCTION(x) "QMetaObject::" x ": " |
476 | |
477 | void tst_QMetaObject::connectSlotsByName() |
478 | { |
479 | CTestObject obj; |
480 | QCOMPARE(obj.invokeCount1, 0); |
481 | QCOMPARE(obj.invokeCount2, 0); |
482 | |
483 | QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName" ) "No matching signal for on_child1_destroyed(QObject*)" ); |
484 | QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName" ) "No matching signal for on_child2_destroyed()" ); |
485 | obj.fire("bubu" ); |
486 | QCOMPARE(obj.invokeCount1, 0); |
487 | QCOMPARE(obj.invokeCount2, 0); |
488 | |
489 | QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName" ) "No matching signal for on_child2_destroyed()" ); |
490 | obj.fire("child1" ); |
491 | QCOMPARE(obj.invokeCount1, 1); |
492 | QCOMPARE(obj.invokeCount2, 0); |
493 | |
494 | QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName" ) "No matching signal for on_child1_destroyed(QObject*)" ); |
495 | obj.fire("child2" ); |
496 | QCOMPARE(obj.invokeCount1, 1); |
497 | QCOMPARE(obj.invokeCount2, 1); |
498 | |
499 | QTest::ignoreMessage(QtWarningMsg, FUNCTION("connectSlotsByName" ) "No matching signal for on_child2_destroyed()" ); |
500 | obj.fire("child1" ); |
501 | QCOMPARE(obj.invokeCount1, 2); |
502 | QCOMPARE(obj.invokeCount2, 1); |
503 | |
504 | // now test with real overloads |
505 | CTestObjectOverloads obj2; |
506 | obj2.fire("child1" ); |
507 | QCOMPARE(obj2.invokeCount1, 1); |
508 | QCOMPARE(obj2.invokeCount2, 1); |
509 | } |
510 | |
511 | struct MyUnregisteredType { }; |
512 | |
513 | static int countedStructObjectsCount = 0; |
514 | struct CountedStruct |
515 | { |
516 | CountedStruct() { ++countedStructObjectsCount; } |
517 | CountedStruct(const CountedStruct &) { ++countedStructObjectsCount; } |
518 | CountedStruct &operator=(const CountedStruct &) { return *this; } |
519 | ~CountedStruct() { --countedStructObjectsCount; } |
520 | }; |
521 | |
522 | #ifndef QT_NO_EXCEPTIONS |
523 | class ObjectException : public std::exception { }; |
524 | #endif |
525 | |
526 | W_REGISTER_ARGTYPE(QString&) |
527 | W_REGISTER_ARGTYPE(QThread*) |
528 | W_REGISTER_ARGTYPE(MyUnregisteredType) |
529 | W_REGISTER_ARGTYPE(CountedStruct) |
530 | |
531 | class QtTestObject: public QObject |
532 | { |
533 | friend class tst_QMetaObject; |
534 | W_OBJECT(QtTestObject) |
535 | |
536 | public: |
537 | QtTestObject(); |
538 | QtTestObject(const QString &s) : slotResult(s) {} |
539 | QtTestObject(QObject *parent); |
540 | W_CONSTRUCTOR(QObject*) |
541 | |
542 | public slots: |
543 | void sl0(); |
544 | W_SLOT(sl0) |
545 | QString sl1(QString s1); |
546 | W_SLOT(sl1) |
547 | void sl2(QString s1, QString s2); |
548 | W_SLOT(sl2) |
549 | void sl3(QString s1, QString s2, QString s3); |
550 | W_SLOT(sl3) |
551 | void sl4(QString s1, QString s2, QString s3, const QString s4); |
552 | W_SLOT(sl4) |
553 | void sl5(QString s1, QString s2, QString s3, QString s4, const QString &s5); |
554 | W_SLOT(sl5) |
555 | void sl6(QString s1, QString s2, QString s3, QString s4, const QString s5, QString s6); |
556 | W_SLOT(sl6) |
557 | void sl7(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7); |
558 | W_SLOT(sl7) |
559 | void sl8(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, |
560 | QString s8); |
561 | W_SLOT(sl8) |
562 | void sl9(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, |
563 | QString s8, QString s9); |
564 | W_SLOT(sl9) |
565 | void sl10(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, |
566 | QString s8, QString s9, QString s10); |
567 | W_SLOT(sl10) |
568 | QObject *sl11(); |
569 | W_SLOT(sl11) |
570 | const char *sl12(); |
571 | W_SLOT(sl12) |
572 | QList<QString> sl13(QList<QString> l1); |
573 | W_SLOT(sl13) |
574 | qint64 sl14(); |
575 | W_SLOT(sl14) |
576 | void testSender(); |
577 | W_SLOT(testSender) |
578 | |
579 | void testReference(QString &str); |
580 | W_SLOT(testReference) |
581 | void testLongLong(qint64 ll1, quint64 ll2); |
582 | W_SLOT(testLongLong) |
583 | void moveToThread(QThread *t) |
584 | { QObject::moveToThread(t); } |
585 | W_SLOT(moveToThread) |
586 | |
587 | void slotWithUnregisteredParameterType(MyUnregisteredType); |
588 | W_SLOT(slotWithUnregisteredParameterType) |
589 | |
590 | CountedStruct throwingSlot(const CountedStruct &, CountedStruct s2) { |
591 | #ifndef QT_NO_EXCEPTIONS |
592 | throw ObjectException(); |
593 | #endif |
594 | return s2; |
595 | } |
596 | W_SLOT(throwingSlot) |
597 | |
598 | void slotWithRegistrableArgument(QtTestObject *o1, QPointer<QtTestObject> o2, |
599 | QSharedPointer<QtTestObject> o3, QWeakPointer<QtTestObject> o4, |
600 | QVector<QtTestObject *> o5, QList<QtTestObject *> o6) |
601 | { |
602 | slotResult = QLatin1String("slotWithRegistrableArgument:" ) + o1->slotResult + o2->slotResult |
603 | + o3->slotResult + o4.data()->slotResult + QString::number(o5.size()) |
604 | + QString::number(o6.size()); |
605 | } |
606 | W_SLOT(slotWithRegistrableArgument, (QtTestObject*, QPointer<QtTestObject>, |
607 | QSharedPointer<QtTestObject>, QWeakPointer<QtTestObject>, |
608 | QVector<QtTestObject*>,QList<QtTestObject*>)) |
609 | |
610 | public: |
611 | static void staticFunction0(); |
612 | static qint64 staticFunction1(); |
613 | |
614 | signals: |
615 | void sig0() |
616 | W_SIGNAL(sig0) |
617 | QString sig1(QString s1) |
618 | W_SIGNAL(sig1,s1) |
619 | void sig10(QString s1, QString s2, QString s3, QString s4, QString s5, QString s6, QString s7, |
620 | QString s8, QString s9, QString s10) |
621 | W_SIGNAL(sig10,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10) |
622 | |
623 | protected: |
624 | QtTestObject(QVariant) {} |
625 | private: |
626 | QtTestObject(QVariant, QVariant) {} |
627 | |
628 | public: |
629 | QString slotResult; |
630 | static QString staticResult; |
631 | }; |
632 | |
633 | W_OBJECT_IMPL(QtTestObject) |
634 | |
635 | QString QtTestObject::staticResult; |
636 | |
637 | QtTestObject::QtTestObject() |
638 | { |
639 | connect(this, SIGNAL(sig0()), this, SLOT(sl0())); |
640 | connect(this, SIGNAL(sig1(QString)), this, SLOT(sl1(QString))); |
641 | } |
642 | |
643 | QtTestObject::QtTestObject(QObject *parent) |
644 | : QObject(parent) |
645 | { |
646 | } |
647 | |
648 | void QtTestObject::sl0() { slotResult = "sl0" ; } |
649 | QString QtTestObject::sl1(QString s1) { slotResult = "sl1:" + s1; return "yessir" ; } |
650 | void QtTestObject::sl2(QString s1, QString s2) { slotResult = "sl2:" + s1 + s2; } |
651 | void QtTestObject::sl3(QString s1, QString s2, QString s3) |
652 | { slotResult = "sl3:" + s1 + s2 + s3; } |
653 | void QtTestObject::sl4(QString s1, QString s2, QString s3, const QString s4) |
654 | { slotResult = "sl4:" + s1 + s2 + s3 + s4; } |
655 | void QtTestObject::sl5(QString s1, QString s2, QString s3, QString s4, const QString &s5) |
656 | { slotResult = "sl5:" + s1 + s2 + s3 + s4 + s5; } |
657 | void QtTestObject::sl6(QString s1, QString s2, QString s3, QString s4, |
658 | const QString s5, QString s6) |
659 | { slotResult = "sl6:" + s1 + s2 + s3 + s4 + s5 + s6; } |
660 | void QtTestObject::sl7(QString s1, QString s2, QString s3, QString s4, QString s5, |
661 | QString s6, QString s7) |
662 | { slotResult = "sl7:" + s1 + s2 + s3 + s4 + s5 + s6 + s7; } |
663 | void QtTestObject::sl8(QString s1, QString s2, QString s3, QString s4, QString s5, |
664 | QString s6, QString s7, QString s8) |
665 | { slotResult = "sl8:" + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8; } |
666 | void QtTestObject::sl9(QString s1, QString s2, QString s3, QString s4, QString s5, |
667 | QString s6, QString s7, QString s8, QString s9) |
668 | { slotResult = "sl9:" + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9; } |
669 | void QtTestObject::sl10(QString s1, QString s2, QString s3, QString s4, QString s5, |
670 | QString s6, QString s7, QString s8, QString s9, QString s10) |
671 | { slotResult = "sl10:" + s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10; } |
672 | QObject *QtTestObject::sl11() |
673 | { slotResult = "sl11" ; return this; } |
674 | const char *QtTestObject::sl12() |
675 | { slotResult = "sl12" ; return "foo" ; } |
676 | QList<QString> QtTestObject::sl13(QList<QString> l1) |
677 | { slotResult = "sl13" ; return l1; } |
678 | qint64 QtTestObject::sl14() |
679 | { slotResult = "sl14" ; return Q_INT64_C(123456789)*123456789; } |
680 | |
681 | void QtTestObject::testReference(QString &str) |
682 | { slotResult = "testReference:" + str; str = "gotcha" ; } |
683 | |
684 | void QtTestObject::testLongLong(qint64 ll1, quint64 ll2) |
685 | { slotResult = "testLongLong:" + QString::number(ll1) + "," + QString::number(ll2); } |
686 | |
687 | void QtTestObject::testSender() |
688 | { |
689 | slotResult = QString::asprintf("%p" , sender()); |
690 | } |
691 | |
692 | void QtTestObject::slotWithUnregisteredParameterType(MyUnregisteredType) |
693 | { slotResult = "slotWithUnregisteredReturnType" ; } |
694 | |
695 | void QtTestObject::staticFunction0() |
696 | { |
697 | staticResult = "staticFunction0" ; |
698 | } |
699 | |
700 | qint64 QtTestObject::staticFunction1() |
701 | { staticResult = "staticFunction1" ; return Q_INT64_C(123456789)*123456789; } |
702 | |
703 | void tst_QMetaObject::invokeMetaMember() |
704 | { |
705 | QtTestObject obj; |
706 | |
707 | QString t1("1" ); QString t2("2" ); QString t3("3" ); QString t4("4" ); QString t5("5" ); |
708 | QString t6("6" ); QString t7("7" ); QString t8("8" ); QString t9("9" ); QString t10("X" ); |
709 | |
710 | // Test nullptr |
711 | char *nullCharArray = nullptr; |
712 | const char *nullConstCharArray = nullptr; |
713 | QVERIFY(!QMetaObject::invokeMethod(nullptr, nullCharArray)); |
714 | QVERIFY(!QMetaObject::invokeMethod(nullptr, nullConstCharArray)); |
715 | QVERIFY(!QMetaObject::invokeMethod(nullptr, "sl0" )); |
716 | QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray)); |
717 | QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray)); |
718 | QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection)); |
719 | QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection)); |
720 | QVERIFY(!QMetaObject::invokeMethod(&obj, nullCharArray, Qt::AutoConnection, QGenericReturnArgument())); |
721 | QVERIFY(!QMetaObject::invokeMethod(&obj, nullConstCharArray, Qt::AutoConnection, QGenericReturnArgument())); |
722 | |
723 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl0" )); |
724 | QCOMPARE(obj.slotResult, QString("sl0" )); |
725 | |
726 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl1" , Q_ARG(QString, t1))); |
727 | QCOMPARE(obj.slotResult, QString("sl1:1" )); |
728 | |
729 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl2" , Q_ARG(const QString, t1), Q_ARG(QString, t2))); |
730 | QCOMPARE(obj.slotResult, QString("sl2:12" )); |
731 | |
732 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl3" , Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3))); |
733 | QCOMPARE(obj.slotResult, QString("sl3:123" )); |
734 | |
735 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl4" , Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), |
736 | Q_ARG(QString, t4))); |
737 | QCOMPARE(obj.slotResult, QString("sl4:1234" )); |
738 | |
739 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl5" , Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), |
740 | Q_ARG(QString, t4), Q_ARG(QString, "5" ))); |
741 | QCOMPARE(obj.slotResult, QString("sl5:12345" )); |
742 | |
743 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl6" , Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), |
744 | Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6))); |
745 | QCOMPARE(obj.slotResult, QString("sl6:123456" )); |
746 | |
747 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl7" , Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), |
748 | Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), |
749 | Q_ARG(QString, t7))); |
750 | QCOMPARE(obj.slotResult, QString("sl7:1234567" )); |
751 | |
752 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl8" , Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), |
753 | Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), |
754 | Q_ARG(QString, t7), Q_ARG(QString, t8))); |
755 | QCOMPARE(obj.slotResult, QString("sl8:12345678" )); |
756 | |
757 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl9" , Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3), |
758 | Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), |
759 | Q_ARG(QString, t7), Q_ARG(QString, t8), Q_ARG(QString, t9))); |
760 | QCOMPARE(obj.slotResult, QString("sl9:123456789" )); |
761 | |
762 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl11" )); |
763 | QCOMPARE(obj.slotResult, QString("sl11" )); |
764 | |
765 | QVERIFY(QMetaObject::invokeMethod(&obj, "testSender" )); |
766 | QCOMPARE(obj.slotResult, QString("0x0" )); |
767 | |
768 | QString refStr("whatever" ); |
769 | QVERIFY(QMetaObject::invokeMethod(&obj, "testReference" , QGenericArgument("QString&" , &refStr))); |
770 | QCOMPARE(obj.slotResult, QString("testReference:whatever" )); |
771 | QCOMPARE(refStr, QString("gotcha" )); |
772 | |
773 | qint64 ll1 = -1; |
774 | quint64 ll2 = 0; |
775 | QVERIFY(QMetaObject::invokeMethod(&obj, |
776 | "testLongLong" , |
777 | Q_ARG(qint64, ll1), |
778 | Q_ARG(quint64, ll2))); |
779 | QCOMPARE(obj.slotResult, QString("testLongLong:-1,0" )); |
780 | |
781 | QString exp; |
782 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl1" , Q_RETURN_ARG(QString, exp), Q_ARG(QString, "bubu" ))); |
783 | QCOMPARE(exp, QString("yessir" )); |
784 | QCOMPARE(obj.slotResult, QString("sl1:bubu" )); |
785 | |
786 | QObject *ptr = 0; |
787 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl11" , Q_RETURN_ARG(QObject*,ptr))); |
788 | QCOMPARE(ptr, (QObject *)&obj); |
789 | QCOMPARE(obj.slotResult, QString("sl11" )); |
790 | // try again with a space: |
791 | ptr = 0; |
792 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl11" , Q_RETURN_ARG(QObject * , ptr))); |
793 | QCOMPARE(ptr, (QObject *)&obj); |
794 | QCOMPARE(obj.slotResult, QString("sl11" )); |
795 | |
796 | const char *ptr2 = 0; |
797 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl12" , Q_RETURN_ARG(const char*, ptr2))); |
798 | QVERIFY(ptr2 != 0); |
799 | QCOMPARE(obj.slotResult, QString("sl12" )); |
800 | // try again with a space: |
801 | ptr2 = 0; |
802 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl12" , Q_RETURN_ARG(char const * , ptr2))); |
803 | QVERIFY(ptr2 != 0); |
804 | QCOMPARE(obj.slotResult, QString("sl12" )); |
805 | |
806 | // test w/ template args |
807 | QList<QString> returnValue, argument; |
808 | argument << QString("one" ) << QString("two" ) << QString("three" ); |
809 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl13" , |
810 | Q_RETURN_ARG(QList<QString>, returnValue), |
811 | Q_ARG(QList<QString>, argument))); |
812 | QCOMPARE(returnValue, argument); |
813 | QCOMPARE(obj.slotResult, QString("sl13" )); |
814 | |
815 | // return qint64 |
816 | qint64 return64; |
817 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl14" , |
818 | Q_RETURN_ARG(qint64, return64))); |
819 | QCOMPARE(return64, Q_INT64_C(123456789)*123456789); |
820 | QCOMPARE(obj.slotResult, QString("sl14" )); |
821 | |
822 | //test signals |
823 | QVERIFY(QMetaObject::invokeMethod(&obj, "sig0" )); |
824 | QCOMPARE(obj.slotResult, QString("sl0" )); |
825 | |
826 | QVERIFY(QMetaObject::invokeMethod(&obj, "sig1" , Q_ARG(QString, "baba" ))); |
827 | QCOMPARE(obj.slotResult, QString("sl1:baba" )); |
828 | |
829 | exp.clear(); |
830 | QVERIFY(QMetaObject::invokeMethod(&obj, "sig1" , Q_RETURN_ARG(QString, exp), Q_ARG(QString, "hehe" ))); |
831 | QCOMPARE(exp, QString("yessir" )); |
832 | QCOMPARE(obj.slotResult, QString("sl1:hehe" )); |
833 | |
834 | QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()" ); |
835 | QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist" )); |
836 | QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)" ); |
837 | QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)" , Q_ARG(QString, "arg" ))); |
838 | QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n" |
839 | "Candidates are:\n sl3(QString,QString,QString)" ); |
840 | QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3" , Q_ARG(QString, "arg" ))); |
841 | QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" |
842 | "Candidates are:\n sl1(QString)" ); |
843 | QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1" , Q_ARG(QString, "arg" ), Q_ARG(QString, "arg" ), Q_ARG(QString, "arg" ))); |
844 | |
845 | //should not have changed since last test. |
846 | QCOMPARE(exp, QString("yessir" )); |
847 | QCOMPARE(obj.slotResult, QString("sl1:hehe" )); |
848 | } |
849 | |
850 | void testFunction(){} |
851 | |
852 | |
853 | void tst_QMetaObject::invokePointer() |
854 | { |
855 | #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 1) |
856 | QtTestObject obj; |
857 | QtTestObject *const nullTestObject = nullptr; |
858 | |
859 | QString t1("1" ); |
860 | |
861 | // Test member functions |
862 | QVERIFY(!QMetaObject::invokeMethod(nullTestObject, &QtTestObject::sl0)); |
863 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl0)); |
864 | QCOMPARE(obj.slotResult, QString("sl0" )); |
865 | |
866 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::testSender)); |
867 | QCOMPARE(obj.slotResult, QString("0x0" )); |
868 | |
869 | qint64 return64 = 0; |
870 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl14, &return64)); |
871 | QCOMPARE(return64, Q_INT64_C(123456789)*123456789); |
872 | QCOMPARE(obj.slotResult, QString("sl14" )); |
873 | |
874 | // signals |
875 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sig0)); |
876 | QCOMPARE(obj.slotResult, QString("sl0" )); |
877 | |
878 | // Test function pointers |
879 | QVERIFY(!QMetaObject::invokeMethod(0, &testFunction)); |
880 | QVERIFY(QMetaObject::invokeMethod(&obj, &testFunction)); |
881 | |
882 | QVERIFY(!QMetaObject::invokeMethod(0, &QtTestObject::staticFunction0)); |
883 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction0)); |
884 | QCOMPARE(QtTestObject::staticResult, QString("staticFunction0" )); |
885 | |
886 | return64 = 0; |
887 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction1, &return64)); |
888 | QCOMPARE(return64, Q_INT64_C(123456789)*123456789); |
889 | QCOMPARE(QtTestObject::staticResult, QString("staticFunction1" )); |
890 | |
891 | // Test lambdas |
892 | QCOMPARE(countedStructObjectsCount, 0); |
893 | { |
894 | CountedStruct str; |
895 | QVERIFY(QMetaObject::invokeMethod(&obj, [str, &t1, &obj]() { obj.sl1(t1); })); |
896 | QCOMPARE(obj.slotResult, QString("sl1:1" )); |
897 | } |
898 | QCOMPARE(countedStructObjectsCount, 0); |
899 | { |
900 | CountedStruct str; |
901 | QString exp; |
902 | QVERIFY(QMetaObject::invokeMethod( |
903 | &obj, [str, &obj]() -> QString { return obj.sl1("bubu" ); }, &exp)); |
904 | QCOMPARE(exp, QString("yessir" )); |
905 | QCOMPARE(obj.slotResult, QString("sl1:bubu" )); |
906 | } |
907 | QCOMPARE(countedStructObjectsCount, 0); |
908 | #if defined(__cpp_init_captures) && QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) |
909 | { |
910 | CountedStruct str; |
911 | std::unique_ptr<int> ptr( new int ); |
912 | QVERIFY(QMetaObject::invokeMethod(&obj, [str, &t1, &obj, p = std::move(ptr)]() { obj.sl1(t1); })); |
913 | QCOMPARE(obj.slotResult, QString("sl1:1" )); |
914 | } |
915 | QCOMPARE(countedStructObjectsCount, 0); |
916 | #endif |
917 | #endif |
918 | } |
919 | |
920 | void tst_QMetaObject::invokeQueuedMetaMember() |
921 | { |
922 | QtTestObject obj; |
923 | |
924 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl0" , Qt::QueuedConnection)); |
925 | QVERIFY(obj.slotResult.isEmpty()); |
926 | qApp->processEvents(QEventLoop::AllEvents); |
927 | QCOMPARE(obj.slotResult, QString("sl0" )); |
928 | obj.slotResult = QString(); |
929 | |
930 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl1" , Qt::QueuedConnection, Q_ARG(QString, QString("hallo" )))); |
931 | QVERIFY(obj.slotResult.isEmpty()); |
932 | qApp->processEvents(QEventLoop::AllEvents); |
933 | QCOMPARE(obj.slotResult, QString("sl1:hallo" )); |
934 | obj.slotResult = QString(); |
935 | |
936 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl9" , Qt::QueuedConnection, Q_ARG(QString, "1" ), Q_ARG(QString, "2" ), |
937 | Q_ARG(QString, "3" ), Q_ARG(QString, "4" ), Q_ARG(QString, "5" ), |
938 | Q_ARG(QString, "6" ), Q_ARG(QString, "7" ), Q_ARG(QString, "8" ), |
939 | Q_ARG(QString, "9" ))); |
940 | QVERIFY(obj.slotResult.isEmpty()); |
941 | qApp->processEvents(QEventLoop::AllEvents); |
942 | QCOMPARE(obj.slotResult, QString("sl9:123456789" )); |
943 | |
944 | // signals |
945 | |
946 | obj.slotResult.clear(); |
947 | QVERIFY(QMetaObject::invokeMethod(&obj, "sig0" , Qt::QueuedConnection)); |
948 | QVERIFY(obj.slotResult.isEmpty()); |
949 | qApp->processEvents(QEventLoop::AllEvents); |
950 | QCOMPARE(obj.slotResult, QString("sl0" )); |
951 | |
952 | QVERIFY(QMetaObject::invokeMethod(&obj, "sig1" , Qt::QueuedConnection, Q_ARG(QString, "gogo" ))); |
953 | qApp->processEvents(QEventLoop::AllEvents); |
954 | QCOMPARE(obj.slotResult, QString("sl1:gogo" )); |
955 | |
956 | QString exp; |
957 | QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to invoke methods with return values in queued connections" ); |
958 | QVERIFY(!QMetaObject::invokeMethod(&obj, "sig1" , Qt::QueuedConnection, Q_RETURN_ARG(QString, exp), |
959 | Q_ARG(QString, "nono" ))); |
960 | |
961 | qint64 ll1 = -1; |
962 | quint64 ll2 = 0; |
963 | QVERIFY(QMetaObject::invokeMethod(&obj, |
964 | "testLongLong" , |
965 | Qt::QueuedConnection, |
966 | Q_ARG(qint64, ll1), |
967 | Q_ARG(quint64, ll2))); |
968 | qApp->processEvents(QEventLoop::AllEvents); |
969 | QCOMPARE(obj.slotResult, QString("testLongLong:-1,0" )); |
970 | |
971 | obj.slotResult.clear(); |
972 | { |
973 | MyUnregisteredType t; |
974 | QTest::ignoreMessage(QtWarningMsg, "QMetaMethod::invoke: Unable to handle unregistered datatype 'MyUnregisteredType'" ); |
975 | QVERIFY(!QMetaObject::invokeMethod(&obj, "slotWithUnregisteredParameterType" , Qt::QueuedConnection, Q_ARG(MyUnregisteredType, t))); |
976 | QVERIFY(obj.slotResult.isEmpty()); |
977 | } |
978 | } |
979 | |
980 | void tst_QMetaObject::invokeQueuedPointer() |
981 | { |
982 | #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 1) |
983 | QtTestObject obj; |
984 | |
985 | // Test member function |
986 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl0, Qt::QueuedConnection)); |
987 | QVERIFY(obj.slotResult.isEmpty()); |
988 | qApp->processEvents(QEventLoop::AllEvents); |
989 | QCOMPARE(obj.slotResult, QString("sl0" )); |
990 | |
991 | // signals |
992 | obj.slotResult.clear(); |
993 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sig0, Qt::QueuedConnection)); |
994 | QVERIFY(obj.slotResult.isEmpty()); |
995 | qApp->processEvents(QEventLoop::AllEvents); |
996 | QCOMPARE(obj.slotResult, QString("sl0" )); |
997 | |
998 | // Test function pointers |
999 | QtTestObject::staticResult.clear(); |
1000 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction0, Qt::QueuedConnection)); |
1001 | QVERIFY(QtTestObject::staticResult.isEmpty()); |
1002 | qApp->processEvents(QEventLoop::AllEvents); |
1003 | QCOMPARE(QtTestObject::staticResult, QString("staticFunction0" )); |
1004 | |
1005 | // Test lambda |
1006 | QCOMPARE(countedStructObjectsCount, 0); |
1007 | { |
1008 | CountedStruct str; |
1009 | obj.slotResult.clear(); |
1010 | QVERIFY( |
1011 | QMetaObject::invokeMethod(&obj, [str, &obj]() { obj.sl0(); }, Qt::QueuedConnection)); |
1012 | QVERIFY(obj.slotResult.isEmpty()); |
1013 | qApp->processEvents(QEventLoop::AllEvents); |
1014 | QCOMPARE(obj.slotResult, QString("sl0" )); |
1015 | } |
1016 | QCOMPARE(countedStructObjectsCount, 0); |
1017 | { |
1018 | CountedStruct str; |
1019 | qint32 var = 0; |
1020 | QTest::ignoreMessage(QtWarningMsg, |
1021 | "QMetaObject::invokeMethod: Unable to invoke methods with return " |
1022 | "values in queued connections" ); |
1023 | QVERIFY(!QMetaObject::invokeMethod(&obj, [str]() -> qint32 { return 1; }, |
1024 | Qt::QueuedConnection, &var)); |
1025 | QCOMPARE(var, 0); |
1026 | } |
1027 | QCOMPARE(countedStructObjectsCount, 0); |
1028 | #endif |
1029 | } |
1030 | |
1031 | |
1032 | void tst_QMetaObject::invokeBlockingQueuedMetaMember() |
1033 | { |
1034 | QThread t; |
1035 | t.start(); |
1036 | QtTestObject obj; |
1037 | obj.moveToThread(&t); |
1038 | |
1039 | QString t1("1" ); QString t2("2" ); QString t3("3" ); QString t4("4" ); QString t5("5" ); |
1040 | QString t6("6" ); QString t7("7" ); QString t8("8" ); QString t9("9" ); QString t10("X" ); |
1041 | |
1042 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl1" , Qt::BlockingQueuedConnection, Q_ARG(QString, t1))); |
1043 | QCOMPARE(obj.slotResult, QString("sl1:1" )); |
1044 | |
1045 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl2" , Qt::BlockingQueuedConnection, Q_ARG(const QString, t1), Q_ARG(QString, t2))); |
1046 | QCOMPARE(obj.slotResult, QString("sl2:12" )); |
1047 | |
1048 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl3" , Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3))); |
1049 | QCOMPARE(obj.slotResult, QString("sl3:123" )); |
1050 | |
1051 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl4" , Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), |
1052 | Q_ARG(QString, t3), Q_ARG(QString, t4))); |
1053 | QCOMPARE(obj.slotResult, QString("sl4:1234" )); |
1054 | |
1055 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl5" , Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), |
1056 | Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, "5" ))); |
1057 | QCOMPARE(obj.slotResult, QString("sl5:12345" )); |
1058 | |
1059 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl6" , Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), |
1060 | Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6))); |
1061 | QCOMPARE(obj.slotResult, QString("sl6:123456" )); |
1062 | |
1063 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl7" , Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), |
1064 | Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), |
1065 | Q_ARG(QString, t7))); |
1066 | QCOMPARE(obj.slotResult, QString("sl7:1234567" )); |
1067 | |
1068 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl8" , Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), |
1069 | Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), |
1070 | Q_ARG(QString, t7), Q_ARG(QString, t8))); |
1071 | QCOMPARE(obj.slotResult, QString("sl8:12345678" )); |
1072 | |
1073 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl9" , Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), |
1074 | Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6), |
1075 | Q_ARG(QString, t7), Q_ARG(QString, t8), Q_ARG(QString, t9))); |
1076 | QCOMPARE(obj.slotResult, QString("sl9:123456789" )); |
1077 | |
1078 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl11" , Qt::BlockingQueuedConnection)); |
1079 | QCOMPARE(obj.slotResult, QString("sl11" )); |
1080 | |
1081 | QVERIFY(QMetaObject::invokeMethod(&obj, "testSender" , Qt::BlockingQueuedConnection)); |
1082 | QCOMPARE(obj.slotResult, QString("0x0" )); |
1083 | |
1084 | QString refStr("whatever" ); |
1085 | QVERIFY(QMetaObject::invokeMethod(&obj, "testReference" , Qt::BlockingQueuedConnection, QGenericArgument("QString&" , &refStr))); |
1086 | QCOMPARE(obj.slotResult, QString("testReference:whatever" )); |
1087 | QCOMPARE(refStr, QString("gotcha" )); |
1088 | |
1089 | qint64 ll1 = -1; |
1090 | quint64 ll2 = 0; |
1091 | QVERIFY(QMetaObject::invokeMethod(&obj, |
1092 | "testLongLong" , |
1093 | Qt::BlockingQueuedConnection, |
1094 | Q_ARG(qint64, ll1), |
1095 | Q_ARG(quint64, ll2))); |
1096 | QCOMPARE(obj.slotResult, QString("testLongLong:-1,0" )); |
1097 | |
1098 | QString exp; |
1099 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl1" , Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, exp), Q_ARG(QString, "bubu" ))); |
1100 | QCOMPARE(exp, QString("yessir" )); |
1101 | QCOMPARE(obj.slotResult, QString("sl1:bubu" )); |
1102 | |
1103 | QObject *ptr = 0; |
1104 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl11" , Qt::BlockingQueuedConnection, Q_RETURN_ARG(QObject*,ptr))); |
1105 | QCOMPARE(ptr, (QObject *)&obj); |
1106 | QCOMPARE(obj.slotResult, QString("sl11" )); |
1107 | // try again with a space: |
1108 | ptr = 0; |
1109 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl11" , Qt::BlockingQueuedConnection, Q_RETURN_ARG(QObject * , ptr))); |
1110 | QCOMPARE(ptr, (QObject *)&obj); |
1111 | QCOMPARE(obj.slotResult, QString("sl11" )); |
1112 | |
1113 | const char *ptr2 = 0; |
1114 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl12" , Qt::BlockingQueuedConnection, Q_RETURN_ARG(const char*, ptr2))); |
1115 | QVERIFY(ptr2 != 0); |
1116 | QCOMPARE(obj.slotResult, QString("sl12" )); |
1117 | // try again with a space: |
1118 | ptr2 = 0; |
1119 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl12" , Qt::BlockingQueuedConnection, Q_RETURN_ARG(char const * , ptr2))); |
1120 | QVERIFY(ptr2 != 0); |
1121 | QCOMPARE(obj.slotResult, QString("sl12" )); |
1122 | |
1123 | // test w/ template args |
1124 | QList<QString> returnValue, argument; |
1125 | argument << QString("one" ) << QString("two" ) << QString("three" ); |
1126 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl13" , Qt::BlockingQueuedConnection, |
1127 | Q_RETURN_ARG(QList<QString>, returnValue), |
1128 | Q_ARG(QList<QString>, argument))); |
1129 | QCOMPARE(returnValue, argument); |
1130 | QCOMPARE(obj.slotResult, QString("sl13" )); |
1131 | |
1132 | //test signals |
1133 | QVERIFY(QMetaObject::invokeMethod(&obj, "sig0" , Qt::BlockingQueuedConnection)); |
1134 | QCOMPARE(obj.slotResult, QString("sl0" )); |
1135 | |
1136 | QVERIFY(QMetaObject::invokeMethod(&obj, "sig1" , Qt::BlockingQueuedConnection, Q_ARG(QString, "baba" ))); |
1137 | QCOMPARE(obj.slotResult, QString("sl1:baba" )); |
1138 | |
1139 | exp.clear(); |
1140 | QVERIFY(QMetaObject::invokeMethod(&obj, "sig1" , Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, exp), Q_ARG(QString, "hehe" ))); |
1141 | QCOMPARE(exp, QString("yessir" )); |
1142 | QCOMPARE(obj.slotResult, QString("sl1:hehe" )); |
1143 | |
1144 | QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()" ); |
1145 | QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist" , Qt::BlockingQueuedConnection)); |
1146 | QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)" ); |
1147 | QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)" , Qt::BlockingQueuedConnection, Q_ARG(QString, "arg" ))); |
1148 | QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)\n" |
1149 | "Candidates are:\n sl3(QString,QString,QString)" ); |
1150 | QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3" , Qt::BlockingQueuedConnection, Q_ARG(QString, "arg" ))); |
1151 | QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)\n" |
1152 | "Candidates are:\n sl1(QString)" ); |
1153 | QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1" , Qt::BlockingQueuedConnection, Q_ARG(QString, "arg" ), Q_ARG(QString, "arg" ), Q_ARG(QString, "arg" ))); |
1154 | |
1155 | //should not have changed since last test. |
1156 | QCOMPARE(exp, QString("yessir" )); |
1157 | QCOMPARE(obj.slotResult, QString("sl1:hehe" )); |
1158 | |
1159 | QVERIFY(QMetaObject::invokeMethod(&obj, "moveToThread" , Qt::BlockingQueuedConnection, Q_ARG(QThread*, QThread::currentThread()))); |
1160 | t.quit(); |
1161 | QVERIFY(t.wait()); |
1162 | |
1163 | } |
1164 | |
1165 | void tst_QMetaObject::invokeBlockingQueuedPointer() |
1166 | { |
1167 | #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 1) |
1168 | QtTestObject *const nullTestObject = nullptr; |
1169 | |
1170 | QThread t; |
1171 | t.start(); |
1172 | QtTestObject obj; |
1173 | obj.moveToThread(&t); |
1174 | |
1175 | QString t1("1" ); |
1176 | |
1177 | // Test member functions |
1178 | QVERIFY(!QMetaObject::invokeMethod(nullTestObject, &QtTestObject::sl0, Qt::BlockingQueuedConnection)); |
1179 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl0, Qt::BlockingQueuedConnection)); |
1180 | QCOMPARE(obj.slotResult, QString("sl0" )); |
1181 | |
1182 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::testSender, Qt::BlockingQueuedConnection)); |
1183 | QCOMPARE(obj.slotResult, QString("0x0" )); |
1184 | |
1185 | // return qint64 |
1186 | qint64 return64 = 0; |
1187 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sl14, Qt::BlockingQueuedConnection, |
1188 | &return64)); |
1189 | QCOMPARE(return64, Q_INT64_C(123456789)*123456789); |
1190 | QCOMPARE(obj.slotResult, QString("sl14" )); |
1191 | |
1192 | //test signals |
1193 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::sig0, Qt::BlockingQueuedConnection)); |
1194 | QCOMPARE(obj.slotResult, QString("sl0" )); |
1195 | |
1196 | // Test function pointers |
1197 | QVERIFY(!QMetaObject::invokeMethod(0, &testFunction, Qt::BlockingQueuedConnection)); |
1198 | QVERIFY(QMetaObject::invokeMethod(&obj, &testFunction, Qt::BlockingQueuedConnection)); |
1199 | |
1200 | QVERIFY(!QMetaObject::invokeMethod(0, &QtTestObject::staticFunction0, Qt::BlockingQueuedConnection)); |
1201 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction0, Qt::BlockingQueuedConnection)); |
1202 | QCOMPARE(QtTestObject::staticResult, QString("staticFunction0" )); |
1203 | |
1204 | return64 = 0; |
1205 | QVERIFY(QMetaObject::invokeMethod(&obj, &QtTestObject::staticFunction1, Qt::BlockingQueuedConnection, &return64)); |
1206 | QCOMPARE(return64, Q_INT64_C(123456789)*123456789); |
1207 | QCOMPARE(QtTestObject::staticResult, QString("staticFunction1" )); |
1208 | |
1209 | // Test lambdas |
1210 | QCOMPARE(countedStructObjectsCount, 0); |
1211 | { |
1212 | CountedStruct str; |
1213 | QVERIFY(QMetaObject::invokeMethod(&obj, [str, &obj, &t1]() { obj.sl1(t1); }, |
1214 | Qt::BlockingQueuedConnection)); |
1215 | QCOMPARE(obj.slotResult, QString("sl1:1" )); |
1216 | } |
1217 | { |
1218 | CountedStruct str; |
1219 | QString exp; |
1220 | QVERIFY(QMetaObject::invokeMethod(&obj, |
1221 | [&obj, str]() -> QString { return obj.sl1("bubu" ); }, |
1222 | Qt::BlockingQueuedConnection, &exp)); |
1223 | QCOMPARE(exp, QString("yessir" )); |
1224 | QCOMPARE(obj.slotResult, QString("sl1:bubu" )); |
1225 | } |
1226 | #if defined(__cpp_init_captures) && QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) |
1227 | { |
1228 | std::unique_ptr<int> ptr(new int); |
1229 | QVERIFY(QMetaObject::invokeMethod(&obj, |
1230 | [&obj, p = std::move(ptr)]() { return obj.sl1("hehe" ); }, |
1231 | Qt::BlockingQueuedConnection)); |
1232 | QCOMPARE(obj.slotResult, QString("sl1:hehe" )); |
1233 | } |
1234 | #endif |
1235 | QVERIFY(QMetaObject::invokeMethod(&obj, [&](){obj.moveToThread(QThread::currentThread());}, Qt::BlockingQueuedConnection)); |
1236 | t.quit(); |
1237 | QVERIFY(t.wait()); |
1238 | QCOMPARE(countedStructObjectsCount, 0); |
1239 | #endif |
1240 | } |
1241 | |
1242 | |
1243 | void tst_QMetaObject::qtMetaObjectInheritance() |
1244 | { |
1245 | QVERIFY(!QObject::staticMetaObject.superClass()); |
1246 | QCOMPARE(QSortFilterProxyModel::staticMetaObject.indexOfEnumerator("Qt::CaseSensitivity" ), -1); |
1247 | QCOMPARE(QSortFilterProxyModel::staticMetaObject.indexOfEnumerator("CaseSensitivity" ), -1); |
1248 | int indexOfSortCaseSensitivity = QSortFilterProxyModel::staticMetaObject.indexOfProperty("sortCaseSensitivity" ); |
1249 | QVERIFY(indexOfSortCaseSensitivity != -1); |
1250 | QMetaProperty sortCaseSensitivity = QSortFilterProxyModel::staticMetaObject.property(indexOfSortCaseSensitivity); |
1251 | QVERIFY(sortCaseSensitivity.isValid()); |
1252 | QCOMPARE(sortCaseSensitivity.enumerator().name(), "CaseSensitivity" ); |
1253 | } |
1254 | |
1255 | struct MyType |
1256 | { |
1257 | int i1, i2, i3; |
1258 | }; |
1259 | W_REGISTER_ARGTYPE(MyType) |
1260 | |
1261 | typedef QString CustomString; |
1262 | |
1263 | |
1264 | class QtTestCustomObject: public QObject |
1265 | { |
1266 | W_OBJECT(QtTestCustomObject) |
1267 | friend class tst_QMetaObject; |
1268 | public: |
1269 | QtTestCustomObject(): QObject(), sum(0) {} |
1270 | |
1271 | public slots: |
1272 | void sl1(MyType myType); |
1273 | W_SLOT(sl1) |
1274 | |
1275 | signals: |
1276 | void sig_custom(const CustomString &string) |
1277 | W_SIGNAL(sig_custom,string) |
1278 | |
1279 | public: |
1280 | int sum; |
1281 | }; |
1282 | |
1283 | W_OBJECT_IMPL(QtTestCustomObject) |
1284 | |
1285 | void QtTestCustomObject::sl1(MyType myType) |
1286 | { |
1287 | sum = myType.i1 + myType.i2 + myType.i3; |
1288 | } |
1289 | |
1290 | void tst_QMetaObject::invokeCustomTypes() |
1291 | { |
1292 | QtTestCustomObject obj; |
1293 | MyType tp = {1, 1, 1}; |
1294 | |
1295 | QCOMPARE(obj.sum, 0); |
1296 | QVERIFY(QMetaObject::invokeMethod(&obj, "sl1" , Q_ARG(MyType, tp))); |
1297 | QCOMPARE(obj.sum, 3); |
1298 | } |
1299 | |
1300 | namespace NamespaceWithConstructibleClass |
1301 | { |
1302 | |
1303 | class ConstructibleClass : public QObject |
1304 | { |
1305 | W_OBJECT(ConstructibleClass) |
1306 | public: |
1307 | ConstructibleClass(QObject *parent = 0) |
1308 | : QObject(parent) {} |
1309 | W_CONSTRUCTOR(QObject*) |
1310 | }; |
1311 | |
1312 | } |
1313 | |
1314 | W_OBJECT_IMPL(NamespaceWithConstructibleClass::ConstructibleClass) |
1315 | |
1316 | void tst_QMetaObject::invokeMetaConstructor() |
1317 | { |
1318 | const QMetaObject *mo = &QtTestObject::staticMetaObject; |
1319 | { |
1320 | QObject *obj = mo->newInstance(); |
1321 | QVERIFY(!obj); |
1322 | } |
1323 | { |
1324 | QtTestObject obj; |
1325 | QObject *obj2 = mo->newInstance(Q_ARG(QObject*, &obj)); |
1326 | QVERIFY(obj2 != 0); |
1327 | QCOMPARE(obj2->parent(), (QObject*)&obj); |
1328 | QVERIFY(qobject_cast<QtTestObject*>(obj2) != 0); |
1329 | } |
1330 | // class in namespace |
1331 | const QMetaObject *nsmo = &NamespaceWithConstructibleClass::ConstructibleClass::staticMetaObject; |
1332 | { |
1333 | QtTestObject obj; |
1334 | QObject *obj2 = nsmo->newInstance(Q_ARG(QObject*, &obj)); |
1335 | QVERIFY(obj2 != 0); |
1336 | QCOMPARE(obj2->parent(), (QObject*)&obj); |
1337 | QVERIFY(qobject_cast<NamespaceWithConstructibleClass::ConstructibleClass*>(obj2) != 0); |
1338 | } |
1339 | // gadget shouldn't return a valid pointer |
1340 | #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) |
1341 | { |
1342 | QCOMPARE(MyGadget::staticMetaObject.constructorCount(), 1); |
1343 | QTest::ignoreMessage(QtWarningMsg, "QMetaObject::newInstance: type MyGadget does not inherit QObject" ); |
1344 | QVERIFY(!MyGadget::staticMetaObject.newInstance()); |
1345 | } |
1346 | #endif |
1347 | } |
1348 | |
1349 | void tst_QMetaObject::invokeTypedefTypes() |
1350 | { |
1351 | qRegisterMetaType<CustomString>("CustomString" ); |
1352 | QtTestCustomObject obj; |
1353 | QSignalSpy spy(&obj, &QtTestCustomObject::sig_custom); |
1354 | QVERIFY(spy.isValid()); |
1355 | |
1356 | QCOMPARE(spy.count(), 0); |
1357 | CustomString arg("hello" ); |
1358 | QVERIFY(QMetaObject::invokeMethod(&obj, "sig_custom" , Q_ARG(CustomString, arg))); |
1359 | QCOMPARE(spy.count(), 1); |
1360 | QCOMPARE(spy.at(0).count(), 1); |
1361 | QCOMPARE(spy.at(0).at(0), QVariant(arg)); |
1362 | } |
1363 | |
1364 | void tst_QMetaObject::invokeException() |
1365 | { |
1366 | #ifndef QT_NO_EXCEPTIONS |
1367 | QtTestObject obj; |
1368 | QCOMPARE(countedStructObjectsCount, 0); |
1369 | try { |
1370 | CountedStruct s; |
1371 | QVERIFY(QMetaObject::invokeMethod(&obj, "throwingSlot" , Q_RETURN_ARG(CountedStruct, s), |
1372 | Q_ARG(CountedStruct, s), Q_ARG(CountedStruct, s))); |
1373 | QFAIL("Did not throw" ); |
1374 | } catch(ObjectException &) {} |
1375 | QCOMPARE(countedStructObjectsCount, 0); |
1376 | #else |
1377 | QSKIP("Needs exceptions" ); |
1378 | #endif |
1379 | } |
1380 | |
1381 | void tst_QMetaObject::invokeQueuedAutoRegister() |
1382 | { |
1383 | #if QT_VERSION < QT_VERSION_CHECK(5, 9, 0) |
1384 | QSKIP("Bug fixed in Qt 5.9" ); |
1385 | #endif |
1386 | |
1387 | QtTestObject obj; |
1388 | |
1389 | auto shared = QSharedPointer<QtTestObject>::create(QStringLiteral("myShared-" )); |
1390 | |
1391 | QVERIFY(QMetaObject::invokeMethod( |
1392 | &obj, "slotWithRegistrableArgument" , Qt::QueuedConnection, |
1393 | Q_ARG(QtTestObject *, shared.data()), Q_ARG(QPointer<QtTestObject>, shared.data()), |
1394 | Q_ARG(QSharedPointer<QtTestObject>, shared), Q_ARG(QWeakPointer<QtTestObject>, shared), |
1395 | Q_ARG(QVector<QtTestObject *>, QVector<QtTestObject *>()), |
1396 | Q_ARG(QList<QtTestObject *>, QList<QtTestObject *>()))); |
1397 | QVERIFY(obj.slotResult.isEmpty()); |
1398 | qApp->processEvents(QEventLoop::AllEvents); |
1399 | QCOMPARE(obj.slotResult, |
1400 | QString("slotWithRegistrableArgument:myShared-myShared-myShared-myShared-00" )); |
1401 | } |
1402 | |
1403 | void tst_QMetaObject::normalizedSignature_data() |
1404 | { |
1405 | QTest::addColumn<QString>("signature" ); |
1406 | QTest::addColumn<QString>("result" ); |
1407 | |
1408 | QTest::newRow("function" ) << "void foo()" << "void foo()" ; |
1409 | QTest::newRow("spaces" ) << " void foo( ) " << "void foo()" ; |
1410 | QTest::newRow("void" ) << "void foo(void)" << "void foo()" ; |
1411 | QTest::newRow("void spaces" ) << "void foo( void )" << "void foo()" ; |
1412 | QTest::newRow("void*" ) << "void foo(void*)" << "void foo(void*)" ; |
1413 | QTest::newRow("void* spaces" ) << "void foo( void * )" << "void foo(void*)" ; |
1414 | QTest::newRow("function ptr" ) << "void foo(void(*)(void))" << "void foo(void(*)())" ; |
1415 | QTest::newRow("function ptr spaces" ) << "void foo( void ( * ) ( void ))" << "void foo(void(*)())" ; |
1416 | QTest::newRow("function ptr void*" ) << "void foo(void(*)(void*))" << "void foo(void(*)(void*))" ; |
1417 | QTest::newRow("function ptr void* spaces" ) << "void foo( void ( * ) ( void * ))" << "void foo(void(*)(void*))" ; |
1418 | QTest::newRow("template args" ) << " void foo( QMap<a, a>, QList<b>) " |
1419 | << "void foo(QMap<a,a>,QList<b>)" ; |
1420 | QTest::newRow("void template args" ) << " void foo( Foo<void>, Bar<void> ) " |
1421 | << "void foo(Foo<void>,Bar<void>)" ; |
1422 | QTest::newRow("void* template args" ) << " void foo( Foo<void*>, Bar<void *> ) " |
1423 | << "void foo(Foo<void*>,Bar<void*>)" ; |
1424 | QTest::newRow("rettype" ) << "QList<int, int> foo()" << "QList<int,int>foo()" ; |
1425 | QTest::newRow("rettype void template" ) << "Foo<void> foo()" << "Foo<void>foo()" ; |
1426 | QTest::newRow("const rettype" ) << "const QString *foo()" << "const QString*foo()" ; |
1427 | QTest::newRow("const ref" ) << "const QString &foo()" << "const QString&foo()" ; |
1428 | QTest::newRow("reference" ) << "QString &foo()" << "QString&foo()" ; |
1429 | QTest::newRow("const1" ) << "void foo(QString const *)" << "void foo(const QString*)" ; |
1430 | QTest::newRow("const2" ) << "void foo(QString * const)" << "void foo(QString*const)" ; |
1431 | QTest::newRow("const3" ) << "void foo(QString const &)" << "void foo(QString)" ; |
1432 | QTest::newRow("const4" ) << "void foo(const int)" << "void foo(int)" ; |
1433 | QTest::newRow("const5" ) << "void foo(const int, int const, const int &, int const &)" |
1434 | << "void foo(int,int,int,int)" ; |
1435 | QTest::newRow("const6" ) << "void foo(QList<const int>)" << "void foo(QList<const int>)" ; |
1436 | QTest::newRow("const7" ) << "void foo(QList<const int*>)" << "void foo(QList<const int*>)" ; |
1437 | QTest::newRow("const8" ) << "void foo(QList<int const*>)" << "void foo(QList<const int*>)" ; |
1438 | QTest::newRow("const9" ) << "void foo(const Foo<Bar>)" << "void foo(Foo<Bar>)" ; |
1439 | QTest::newRow("const10" ) << "void foo(Foo<Bar>const)" << "void foo(Foo<Bar>)" ; |
1440 | QTest::newRow("const11" ) << "void foo(Foo<Bar> *const)" << "void foo(Foo<Bar>*const)" ; |
1441 | QTest::newRow("const12" ) << "void foo(Foo<Bar>const*const *const)" << "void foo(Foo<Bar>*const*const)" ; |
1442 | QTest::newRow("const13" ) << "void foo(const Foo<Bar>&)" << "void foo(Foo<Bar>)" ; |
1443 | QTest::newRow("const14" ) << "void foo(Foo<Bar>const&)" << "void foo(Foo<Bar>)" ; |
1444 | |
1445 | QTest::newRow("invalid1" ) << "a( b" << "a(b" ; |
1446 | } |
1447 | |
1448 | void tst_QMetaObject::normalizedSignature() |
1449 | { |
1450 | QFETCH(QString, signature); |
1451 | QFETCH(QString, result); |
1452 | |
1453 | QCOMPARE(QMetaObject::normalizedSignature(signature.toLatin1()), result.toLatin1()); |
1454 | } |
1455 | |
1456 | void tst_QMetaObject::normalizedType_data() |
1457 | { |
1458 | QTest::addColumn<QString>("type" ); |
1459 | QTest::addColumn<QString>("result" ); |
1460 | |
1461 | QTest::newRow("simple" ) << "int" << "int" ; |
1462 | QTest::newRow("white" ) << " int " << "int" ; |
1463 | QTest::newRow("const1" ) << "int const *" << "const int*" ; |
1464 | QTest::newRow("const2" ) << "const int *" << "const int*" ; |
1465 | QTest::newRow("template1" ) << "QList<int const *>" << "QList<const int*>" ; |
1466 | QTest::newRow("template2" ) << "QList<const int *>" << "QList<const int*>" ; |
1467 | QTest::newRow("template3" ) << "QMap<QString, int>" << "QMap<QString,int>" ; |
1468 | QTest::newRow("template4" ) << "const QMap<QString, int> &" << "QMap<QString,int>" ; |
1469 | QTest::newRow("template5" ) << "QList< ::Foo::Bar>" << "QList< ::Foo::Bar>" ; |
1470 | QTest::newRow("template6" ) << "QList<::Foo::Bar>" << "QList<::Foo::Bar>" ; |
1471 | QTest::newRow("template7" ) << "QList<QList<int> >" << "QList<QList<int> >" ; |
1472 | QTest::newRow("template8" ) << "QMap<const int, const short*>" << "QMap<const int,const short*>" ; |
1473 | QTest::newRow("template9" ) << "QPair<const QPair<int, int const *> , QPair<QHash<int, const char*> > >" << "QPair<const QPair<int,const int*>,QPair<QHash<int,const char*> > >" ; |
1474 | QTest::newRow("value1" ) << "const QString &" << "QString" ; |
1475 | QTest::newRow("value2" ) << "QString const &" << "QString" ; |
1476 | QTest::newRow("constInName1" ) << "constconst" << "constconst" ; |
1477 | QTest::newRow("constInName2" ) << "constconst*" << "constconst*" ; |
1478 | QTest::newRow("constInName3" ) << "const constconst&" << "constconst" ; |
1479 | QTest::newRow("constInName4" ) << "constconst const*const" << "constconst*const" ; |
1480 | QTest::newRow("class" ) << "const class foo&" << "foo" ; |
1481 | QTest::newRow("struct" ) << "const struct foo*" << "const foo*" ; |
1482 | QTest::newRow("struct2" ) << "struct foo const*" << "const foo*" ; |
1483 | QTest::newRow("enum" ) << "enum foo" << "foo" ; |
1484 | QTest::newRow("void" ) << "void" << "void" ; |
1485 | } |
1486 | |
1487 | void tst_QMetaObject::normalizedType() |
1488 | { |
1489 | QFETCH(QString, type); |
1490 | QFETCH(QString, result); |
1491 | |
1492 | QCOMPARE(QMetaObject::normalizedType(type.toLatin1()), result.toLatin1()); |
1493 | } |
1494 | |
1495 | void tst_QMetaObject::customPropertyType() |
1496 | { |
1497 | QMetaProperty prop = metaObject()->property(metaObject()->indexOfProperty("value3" )); |
1498 | |
1499 | QCOMPARE(prop.type(), QVariant::UserType); |
1500 | QCOMPARE(prop.userType(), 0); |
1501 | |
1502 | qRegisterMetaType<MyStruct>("MyStruct" ); |
1503 | QCOMPARE(prop.userType(), QMetaType::type("MyStruct" )); |
1504 | |
1505 | prop = metaObject()->property(metaObject()->indexOfProperty("value4" )); |
1506 | QCOMPARE(prop.type(), QVariant::List); |
1507 | |
1508 | prop = metaObject()->property(metaObject()->indexOfProperty("value5" )); |
1509 | QCOMPARE(prop.type(), QVariant::List); |
1510 | } |
1511 | |
1512 | void tst_QMetaObject::checkScope_data() |
1513 | { |
1514 | QTest::addColumn<QObject *>("object" ); |
1515 | QTest::addColumn<QByteArray>("name" ); |
1516 | |
1517 | static MyNamespace::MyClass obj1; |
1518 | static MyNamespace::MyClass2 obj2; |
1519 | |
1520 | QTest::newRow("MyClass" ) << static_cast<QObject*>(&obj1) << QByteArray("MyClass" ); |
1521 | QTest::newRow("MyClass2" ) << static_cast<QObject*>(&obj2) << QByteArray("MyClass2" ); |
1522 | |
1523 | } |
1524 | |
1525 | |
1526 | void tst_QMetaObject::checkScope() |
1527 | { |
1528 | QFETCH(QObject *, object); |
1529 | QFETCH(QByteArray, name); |
1530 | QObject &obj = *object; |
1531 | bool ok; |
1532 | |
1533 | const QMetaObject *mo = obj.metaObject(); |
1534 | QMetaEnum me = mo->enumerator(mo->indexOfEnumerator("MyEnum" )); |
1535 | QVERIFY(me.isValid()); |
1536 | QVERIFY(!me.isFlag()); |
1537 | QCOMPARE(QByteArray(me.scope()), QByteArray("MyNamespace::" + name)); |
1538 | QCOMPARE(me.keyToValue("MyNamespace::" + name + "::MyEnum2" , &ok), 1); |
1539 | QCOMPARE(ok, true); |
1540 | QCOMPARE(me.keyToValue(name + "::MyEnum2" , &ok), -1); |
1541 | QCOMPARE(ok, false); |
1542 | QCOMPARE(me.keyToValue("MyNamespace::MyEnum2" , &ok), -1); |
1543 | QCOMPARE(ok, false); |
1544 | QCOMPARE(me.keyToValue("MyEnum2" , &ok), 1); |
1545 | QCOMPARE(ok, true); |
1546 | QCOMPARE(me.keyToValue("MyEnum" , &ok), -1); |
1547 | QCOMPARE(ok, false); |
1548 | QCOMPARE(QLatin1String(me.valueToKey(1)), QLatin1String("MyEnum2" )); |
1549 | |
1550 | QMetaEnum me2 = mo->enumerator(mo->indexOfEnumerator("MyAnotherEnum" )); |
1551 | QVERIFY(me2.isValid()); |
1552 | QVERIFY(!me2.isFlag()); |
1553 | QCOMPARE(me2.keyToValue("MyAnotherEnum1" , &ok), 1); |
1554 | QCOMPARE(ok, true); |
1555 | QCOMPARE(me2.keyToValue("MyAnotherEnum2" , &ok), 2); |
1556 | QCOMPARE(ok, true); |
1557 | QCOMPARE(me2.keyToValue("MyAnotherEnum3" , &ok), -1); |
1558 | QCOMPARE(ok, true); |
1559 | QCOMPARE(me2.keyToValue("MyAnotherEnum" , &ok), -1); |
1560 | QCOMPARE(ok, false); |
1561 | |
1562 | QMetaEnum mf = mo->enumerator(mo->indexOfEnumerator("MyFlags" )); |
1563 | QVERIFY(mf.isValid()); |
1564 | QVERIFY(mf.isFlag()); |
1565 | QCOMPARE(QByteArray(mf.scope()), QByteArray("MyNamespace::" + name)); |
1566 | QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag2" , &ok), 2); |
1567 | QCOMPARE(ok, true); |
1568 | QCOMPARE(mf.keysToValue(name + "::MyFlag2" , &ok), -1); |
1569 | QCOMPARE(ok, false); |
1570 | QCOMPARE(mf.keysToValue("MyNamespace::MyFlag2" , &ok), -1); |
1571 | QCOMPARE(ok, false); |
1572 | QCOMPARE(mf.keysToValue("MyFlag2" , &ok), 2); |
1573 | QCOMPARE(ok, true); |
1574 | QCOMPARE(mf.keysToValue("MyFlag" , &ok), -1); |
1575 | QCOMPARE(ok, false); |
1576 | QCOMPARE(QLatin1String(mf.valueToKey(2)), QLatin1String("MyFlag2" )); |
1577 | QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag1|MyNamespace::" + name + "::MyFlag2" , &ok), 3); |
1578 | QCOMPARE(ok, true); |
1579 | QCOMPARE(mf.keysToValue(name + "::MyFlag1|" + name + "::MyFlag2" , &ok), -1); |
1580 | QCOMPARE(ok, false); |
1581 | QCOMPARE(mf.keysToValue("MyNamespace::MyFlag1|MyNamespace::MyFlag2" , &ok), -1); |
1582 | QCOMPARE(ok, false); |
1583 | QCOMPARE(mf.keysToValue("MyFlag1|MyFlag2" , &ok), 3); |
1584 | QCOMPARE(ok, true); |
1585 | QCOMPARE(mf.keysToValue("MyFlag2|MyFlag2" , &ok), 2); |
1586 | QCOMPARE(ok, true); |
1587 | QCOMPARE(mf.keysToValue("MyFlag1|MyNamespace::" + name + "::MyFlag2" , &ok), 3); |
1588 | QCOMPARE(ok, true); |
1589 | QCOMPARE(mf.keysToValue("MyNamespace::" + name + "::MyFlag2|MyNamespace::" + name + "::MyFlag2" , &ok), 2); |
1590 | QCOMPARE(ok, true); |
1591 | QCOMPARE(QLatin1String(mf.valueToKeys(3)), QLatin1String("MyFlag1|MyFlag2" )); |
1592 | } |
1593 | |
1594 | void tst_QMetaObject::propertyNotify() |
1595 | { |
1596 | const QMetaObject *mo = metaObject(); |
1597 | |
1598 | QMetaProperty prop = mo->property(mo->indexOfProperty("value6" )); |
1599 | QVERIFY(prop.isValid()); |
1600 | QVERIFY(prop.hasNotifySignal()); |
1601 | QMetaMethod signal = prop.notifySignal(); |
1602 | QCOMPARE(signal.methodSignature(), QByteArray("value6Changed()" )); |
1603 | |
1604 | prop = mo->property(mo->indexOfProperty("value7" )); |
1605 | QVERIFY(prop.isValid()); |
1606 | QVERIFY(prop.hasNotifySignal()); |
1607 | signal = prop.notifySignal(); |
1608 | QCOMPARE(signal.methodSignature(), QByteArray("value7Changed(QString)" )); |
1609 | |
1610 | prop = mo->property(mo->indexOfProperty("value8" )); |
1611 | QVERIFY(prop.isValid()); |
1612 | QVERIFY(!prop.hasNotifySignal()); |
1613 | signal = prop.notifySignal(); |
1614 | QCOMPARE(signal.methodSignature(), QByteArray()); |
1615 | |
1616 | prop = mo->property(mo->indexOfProperty("value" )); |
1617 | QVERIFY(prop.isValid()); |
1618 | QVERIFY(!prop.hasNotifySignal()); |
1619 | signal = prop.notifySignal(); |
1620 | QCOMPARE(signal.methodSignature(), QByteArray()); |
1621 | } |
1622 | |
1623 | void tst_QMetaObject::propertyConstant() |
1624 | { |
1625 | const QMetaObject *mo = metaObject(); |
1626 | |
1627 | QMetaProperty prop = mo->property(mo->indexOfProperty("value8" )); |
1628 | QVERIFY(prop.isValid()); |
1629 | QVERIFY(!prop.isConstant()); |
1630 | |
1631 | prop = mo->property(mo->indexOfProperty("value9" )); |
1632 | QVERIFY(prop.isValid()); |
1633 | QVERIFY(prop.isConstant()); |
1634 | } |
1635 | |
1636 | void tst_QMetaObject::propertyFinal() |
1637 | { |
1638 | const QMetaObject *mo = metaObject(); |
1639 | |
1640 | QMetaProperty prop = mo->property(mo->indexOfProperty("value10" )); |
1641 | QVERIFY(prop.isValid()); |
1642 | QVERIFY(prop.isFinal()); |
1643 | |
1644 | prop = mo->property(mo->indexOfProperty("value9" )); |
1645 | QVERIFY(prop.isValid()); |
1646 | QVERIFY(!prop.isFinal()); |
1647 | } |
1648 | |
1649 | class ClassInfoTestObjectA : public QObject |
1650 | { |
1651 | W_OBJECT(ClassInfoTestObjectA) |
1652 | W_CLASSINFO("Author" , "Christopher Pike" ) |
1653 | }; |
1654 | |
1655 | W_OBJECT_IMPL(ClassInfoTestObjectA) |
1656 | |
1657 | class ClassInfoTestObjectB : public ClassInfoTestObjectA |
1658 | { |
1659 | W_OBJECT(ClassInfoTestObjectB) |
1660 | }; |
1661 | |
1662 | W_OBJECT_IMPL(ClassInfoTestObjectB) |
1663 | |
1664 | void tst_QMetaObject::classInfo() |
1665 | { |
1666 | ClassInfoTestObjectB b; |
1667 | int index = b.metaObject()->indexOfClassInfo("Author" ); |
1668 | QCOMPARE(index, 0); |
1669 | QVERIFY(index <= b.metaObject()->classInfoOffset()); |
1670 | QCOMPARE(QLatin1String(b.metaObject()->classInfo(index).value()), QLatin1String("Christopher Pike" )); |
1671 | } |
1672 | |
1673 | void tst_QMetaObject::metaMethod() |
1674 | { |
1675 | QString str("foo" ); |
1676 | QString ret("bar" ); |
1677 | QMetaMethod method; |
1678 | QVERIFY(!method.invoke(this)); |
1679 | QVERIFY(!method.invoke(this, Q_ARG(QString, str))); |
1680 | QVERIFY(!method.invoke(this, Q_RETURN_ARG(QString, ret), Q_ARG(QString, str))); |
1681 | QCOMPARE(str, QString("foo" )); |
1682 | QCOMPARE(ret, QString("bar" )); |
1683 | |
1684 | QtTestObject obj; |
1685 | QString t1("1" ); QString t2("2" ); QString t3("3" ); QString t4("4" ); QString t5("5" ); |
1686 | QString t6("6" ); QString t7("7" ); QString t8("8" ); QString t9("9" ); QString t10("X" ); |
1687 | |
1688 | int index = QtTestObject::staticMetaObject.indexOfMethod("sl5(QString,QString,QString,QString,QString)" ); |
1689 | QVERIFY(index > 0); |
1690 | method = QtTestObject::staticMetaObject.method(index); |
1691 | //wrong args |
1692 | QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1" ), Q_ARG(QString, "2" ), Q_ARG(QString, "3" ), Q_ARG(QString, "4" ))); |
1693 | //QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"), Q_ARG(QString, "6"))); |
1694 | //QVERIFY(!method.invoke(&obj, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(int, 5))); |
1695 | QVERIFY(!method.invoke(&obj, Q_RETURN_ARG(QString, ret), Q_ARG(QString, "1" ), Q_ARG(QString, "2" ), Q_ARG(QString, "3" ), Q_ARG(QString, "4" ), Q_ARG(QString, "5" ))); |
1696 | |
1697 | //wrong object |
1698 | //QVERIFY(!method.invoke(this, Q_ARG(QString, "1"), Q_ARG(QString, "2"), Q_ARG(QString, "3"), Q_ARG(QString, "4"), Q_ARG(QString, "5"))); |
1699 | QVERIFY(!method.invoke(0, Q_ARG(QString, "1" ), Q_ARG(QString, "2" ), Q_ARG(QString, "3" ), Q_ARG(QString, "4" ), Q_ARG(QString, "5" ))); |
1700 | QCOMPARE(ret, QString("bar" )); |
1701 | QCOMPARE(obj.slotResult, QString()); |
1702 | |
1703 | QVERIFY(method.invoke(&obj, Q_ARG(QString, "1" ), Q_ARG(QString, "2" ), Q_ARG(QString, "3" ), Q_ARG(QString, "4" ), Q_ARG(QString, "5" ))); |
1704 | QCOMPARE(obj.slotResult, QString("sl5:12345" )); |
1705 | |
1706 | index = QtTestObject::staticMetaObject.indexOfMethod("sl13(QList<QString>)" ); |
1707 | QVERIFY(index > 0); |
1708 | QMetaMethod sl13 = QtTestObject::staticMetaObject.method(index); |
1709 | QList<QString> returnValue, argument; |
1710 | argument << QString("one" ) << QString("two" ) << QString("three" ); |
1711 | //wrong object |
1712 | //QVERIFY(!sl13.invoke(this, Q_RETURN_ARG(QList<QString>, returnValue), Q_ARG(QList<QString>, argument))); |
1713 | QVERIFY(!sl13.invoke(0, Q_RETURN_ARG(QList<QString>, returnValue), Q_ARG(QList<QString>, argument))); |
1714 | QCOMPARE(returnValue, QList<QString>()); |
1715 | |
1716 | QVERIFY(sl13.invoke(&obj, Q_RETURN_ARG(QList<QString>, returnValue), Q_ARG(QList<QString>, argument))); |
1717 | QCOMPARE(returnValue, argument); |
1718 | QCOMPARE(obj.slotResult, QString("sl13" )); |
1719 | } |
1720 | |
1721 | void tst_QMetaObject::indexOfMethod_data() |
1722 | { |
1723 | QTest::addColumn<QObject *>("object" ); |
1724 | QTest::addColumn<QByteArray>("name" ); |
1725 | QTest::addColumn<bool>("isSignal" ); |
1726 | QTest::newRow("indexOfMethod_data" ) << (QObject*)this << QByteArray("indexOfMethod_data()" ) << false; |
1727 | QTest::newRow("deleteLater" ) << (QObject*)this << QByteArray("deleteLater()" ) << false; |
1728 | QTest::newRow("value6changed" ) << (QObject*)this << QByteArray("value6Changed()" ) << true; |
1729 | QTest::newRow("value7changed" ) << (QObject*)this << QByteArray("value7Changed(QString)" ) << true; |
1730 | QTest::newRow("destroyed" ) << (QObject*)this << QByteArray("destroyed()" ) << true; |
1731 | QTest::newRow("destroyed2" ) << (QObject*)this << QByteArray("destroyed(QObject*)" ) << true; |
1732 | } |
1733 | |
1734 | void tst_QMetaObject::indexOfMethod() |
1735 | { |
1736 | QFETCH(QObject *, object); |
1737 | QFETCH(QByteArray, name); |
1738 | QFETCH(bool, isSignal); |
1739 | int idx = object->metaObject()->indexOfMethod(name); |
1740 | QVERIFY(idx >= 0); |
1741 | QCOMPARE(object->metaObject()->method(idx).methodSignature(), name); |
1742 | QCOMPARE(object->metaObject()->indexOfSlot(name), isSignal ? -1 : idx); |
1743 | QCOMPARE(object->metaObject()->indexOfSignal(name), !isSignal ? -1 : idx); |
1744 | } |
1745 | |
1746 | void tst_QMetaObject::indexOfMethodPMF() |
1747 | { |
1748 | #define INDEXOFMETHODPMF_HELPER(ObjectType, Name, Arguments) { \ |
1749 | int idx = -1; \ |
1750 | void (ObjectType::*signal)Arguments = &ObjectType::Name; \ |
1751 | void *signal_p = &signal; \ |
1752 | void *args[] = { &idx, signal_p, 0}; \ |
1753 | ObjectType::qt_static_metacall(0, QMetaObject::IndexOfMethod, 0, args); \ |
1754 | QCOMPARE(ObjectType::staticMetaObject.indexOfMethod(QMetaObject::normalizedSignature(#Name #Arguments)), \ |
1755 | ObjectType::staticMetaObject.methodOffset() + idx); \ |
1756 | } |
1757 | |
1758 | INDEXOFMETHODPMF_HELPER(tst_QMetaObject, value7Changed, (const QString&)) |
1759 | INDEXOFMETHODPMF_HELPER(QtTestObject, sig0, ()) |
1760 | INDEXOFMETHODPMF_HELPER(QtTestObject, sig10, (QString,QString,QString,QString,QString,QString,QString,QString,QString,QString)) |
1761 | INDEXOFMETHODPMF_HELPER(QtTestCustomObject, sig_custom, (const CustomString &)) |
1762 | } |
1763 | |
1764 | #ifdef QT_BUILD_INTERNAL |
1765 | namespace SignalTestHelper |
1766 | { |
1767 | // These functions use the public QMetaObject/QMetaMethod API to implement |
1768 | // the functionality of the internal API, and are used to check the results. |
1769 | |
1770 | static int signalCount(const QMetaObject *mo) |
1771 | { |
1772 | int n = 0; |
1773 | for (int i = 0; i < mo->methodCount(); ++i) { |
1774 | QMetaMethod mm = mo->method(i); |
1775 | if (mm.methodType() == QMetaMethod::Signal) |
1776 | ++n; |
1777 | } |
1778 | return n; |
1779 | } |
1780 | |
1781 | static int signalOffset(const QMetaObject *mo) |
1782 | { |
1783 | return mo->superClass() ? signalCount(mo->superClass()) : 0; |
1784 | } |
1785 | |
1786 | static QMetaMethod signal(const QMetaObject *mo, int index) |
1787 | { |
1788 | int k = 0; |
1789 | for (int i = 0; i < mo->methodCount(); ++i) { |
1790 | QMetaMethod mm = mo->method(i); |
1791 | if (mm.methodType() != QMetaMethod::Signal) |
1792 | continue; |
1793 | if (k == index) |
1794 | return mm; |
1795 | ++k; |
1796 | } |
1797 | return QMetaMethod(); |
1798 | } |
1799 | |
1800 | static int signalIndex(const QMetaMethod &mm) |
1801 | { |
1802 | int k = mm.methodIndex(); |
1803 | const QMetaObject *mo = mm.enclosingMetaObject(); |
1804 | for (int i = 0; i < mm.methodIndex(); ++i) { |
1805 | if (mo->method(i).methodType() != QMetaMethod::Signal) |
1806 | --k; |
1807 | } |
1808 | return k; |
1809 | } |
1810 | |
1811 | } // namespace SignalTestHelper |
1812 | |
1813 | void tst_QMetaObject::signalOffset_data() |
1814 | { |
1815 | QTest::addColumn<const QMetaObject *>("metaObject" ); |
1816 | |
1817 | QTest::newRow("QObject" ) << &QObject::staticMetaObject; |
1818 | QTest::newRow("tst_QMetaObject" ) << &tst_QMetaObject::staticMetaObject; |
1819 | QTest::newRow("QtTestObject" ) << &QtTestObject::staticMetaObject; |
1820 | } |
1821 | |
1822 | void tst_QMetaObject::signalOffset() |
1823 | { |
1824 | QFETCH(const QMetaObject *, metaObject); |
1825 | QCOMPARE(QMetaObjectPrivate::signalOffset(metaObject), |
1826 | SignalTestHelper::signalOffset(metaObject)); |
1827 | } |
1828 | |
1829 | void tst_QMetaObject::signalCount_data() |
1830 | { |
1831 | signalOffset_data(); |
1832 | } |
1833 | |
1834 | void tst_QMetaObject::signalCount() |
1835 | { |
1836 | QFETCH(const QMetaObject *, metaObject); |
1837 | QCOMPARE(QMetaObjectPrivate::absoluteSignalCount(metaObject), |
1838 | SignalTestHelper::signalCount(metaObject)); |
1839 | } |
1840 | |
1841 | void tst_QMetaObject::signal_data() |
1842 | { |
1843 | QTest::addColumn<const QMetaObject *>("metaObject" ); |
1844 | QTest::addColumn<int>("index" ); |
1845 | |
1846 | struct SignalTestDataHelper |
1847 | { |
1848 | static void addSignals(const QMetaObject *mo) |
1849 | { |
1850 | int count = SignalTestHelper::signalCount(mo); |
1851 | for (int i = 0; i < count; ++i) { |
1852 | QMetaMethod mm = SignalTestHelper::signal(mo, i); |
1853 | QByteArray tag(mo->className()); |
1854 | tag.append("::" ); |
1855 | tag.append(mm.methodSignature()); |
1856 | QTest::newRow(tag.constData()) << mo << i; |
1857 | } |
1858 | } |
1859 | }; |
1860 | |
1861 | SignalTestDataHelper::addSignals(&QObject::staticMetaObject); |
1862 | SignalTestDataHelper::addSignals(&tst_QMetaObject::staticMetaObject); |
1863 | SignalTestDataHelper::addSignals(&QtTestObject::staticMetaObject); |
1864 | } |
1865 | |
1866 | void tst_QMetaObject::signal() |
1867 | { |
1868 | QFETCH(const QMetaObject *, metaObject); |
1869 | QFETCH(int, index); |
1870 | |
1871 | QCOMPARE(QMetaObjectPrivate::signal(metaObject, index), |
1872 | SignalTestHelper::signal(metaObject, index)); |
1873 | } |
1874 | |
1875 | void tst_QMetaObject::signalIndex_data() |
1876 | { |
1877 | signal_data(); |
1878 | } |
1879 | |
1880 | void tst_QMetaObject::signalIndex() |
1881 | { |
1882 | QFETCH(const QMetaObject *, metaObject); |
1883 | QFETCH(int, index); |
1884 | |
1885 | QMetaMethod mm = SignalTestHelper::signal(metaObject, index); |
1886 | QCOMPARE(QMetaObjectPrivate::signalIndex(mm), |
1887 | SignalTestHelper::signalIndex(mm)); |
1888 | } |
1889 | #endif |
1890 | |
1891 | void tst_QMetaObject::enumDebugStream_data() |
1892 | { |
1893 | QTest::addColumn<int>("verbosity" ); |
1894 | QTest::addColumn<QString>("normalEnumMsg" ); |
1895 | QTest::addColumn<QString>("scopedEnumMsg" ); |
1896 | QTest::addColumn<QString>("globalEnumMsg" ); |
1897 | QTest::addColumn<QString>("normalFlagMsg" ); |
1898 | QTest::addColumn<QString>("normalFlagsMsg" ); |
1899 | QTest::addColumn<QString>("scopedFlagMsg" ); |
1900 | QTest::addColumn<QString>("scopedFlagsMsg" ); |
1901 | QTest::addColumn<QString>("flagAsEnumMsg" ); |
1902 | |
1903 | QTest::newRow("verbosity=0" ) << 0 |
1904 | << "hello MyEnum2 world" |
1905 | << "hello MyScopedEnum::Enum3 scoped world" |
1906 | << "WindowTitleHint Window Desktop WindowSystemMenuHint" |
1907 | << "hello MyFlag1 world" |
1908 | << "MyFlag1 MyFlag2|MyFlag3" |
1909 | << "MyScopedFlag(MyFlag2)" |
1910 | << "MyScopedFlag(MyFlag2|MyFlag3)" |
1911 | << "MyFlag1" ; |
1912 | |
1913 | QTest::newRow("verbosity=1" ) << 1 |
1914 | << "hello MyEnum::MyEnum2 world" |
1915 | << "hello MyScopedEnum::Enum3 scoped world" |
1916 | << "WindowType::WindowTitleHint WindowType::Window WindowType::Desktop WindowType::WindowSystemMenuHint" |
1917 | << "hello MyFlag(MyFlag1) world" |
1918 | << "MyFlag(MyFlag1) MyFlag(MyFlag2|MyFlag3)" |
1919 | << "MyScopedFlag(MyFlag2)" |
1920 | << "MyScopedFlag(MyFlag2|MyFlag3)" |
1921 | << "MyFlag::MyFlag1" ; |
1922 | |
1923 | QTest::newRow("verbosity=2" ) << 2 |
1924 | << "hello MyNamespace::MyClass::MyEnum2 world" |
1925 | << "hello MyNamespace::MyClass::MyScopedEnum::Enum3 scoped world" |
1926 | << "Qt::WindowTitleHint Qt::Window Qt::Desktop Qt::WindowSystemMenuHint" |
1927 | << "hello QFlags<MyNamespace::MyClass::MyFlag>(MyFlag1) world" |
1928 | << "QFlags<MyNamespace::MyClass::MyFlag>(MyFlag1) QFlags<MyNamespace::MyClass::MyFlag>(MyFlag2|MyFlag3)" |
1929 | << "QFlags<MyNamespace::MyClass::MyScopedFlag>(MyFlag2)" |
1930 | << "QFlags<MyNamespace::MyClass::MyScopedFlag>(MyFlag2|MyFlag3)" |
1931 | << "MyNamespace::MyClass::MyFlag1" ; |
1932 | |
1933 | QTest::newRow("verbosity=3" ) << 3 |
1934 | << "hello MyNamespace::MyClass::MyEnum::MyEnum2 world" |
1935 | << "hello MyNamespace::MyClass::MyScopedEnum::Enum3 scoped world" |
1936 | << "Qt::WindowType::WindowTitleHint Qt::WindowType::Window Qt::WindowType::Desktop Qt::WindowType::WindowSystemMenuHint" |
1937 | << "hello QFlags<MyNamespace::MyClass::MyFlag>(MyFlag1) world" |
1938 | << "QFlags<MyNamespace::MyClass::MyFlag>(MyFlag1) QFlags<MyNamespace::MyClass::MyFlag>(MyFlag2|MyFlag3)" |
1939 | << "QFlags<MyNamespace::MyClass::MyScopedFlag>(MyFlag2)" |
1940 | << "QFlags<MyNamespace::MyClass::MyScopedFlag>(MyFlag2|MyFlag3)" |
1941 | << "MyNamespace::MyClass::MyFlag::MyFlag1" ; |
1942 | } |
1943 | |
1944 | void tst_QMetaObject::enumDebugStream() |
1945 | { |
1946 | #if QT_VERSION < QT_VERSION_CHECK(5, 12, 0) |
1947 | QTest::ignoreMessage(QtDebugMsg, "hello MyNamespace::MyClass::MyEnum(MyEnum2) world " ); |
1948 | MyNamespace::MyClass::MyEnum e = MyNamespace::MyClass::MyEnum2; |
1949 | qDebug() << "hello" << e << "world" ; |
1950 | |
1951 | QTest::ignoreMessage(QtDebugMsg, "Qt::WindowType(WindowTitleHint) Qt::WindowType(Window) Qt::WindowType(Desktop) Qt::WindowType(WindowSystemMenuHint)" ); |
1952 | qDebug() << Qt::WindowTitleHint << Qt::Window <<Qt::Desktop << Qt::WindowSystemMenuHint; |
1953 | |
1954 | QTest::ignoreMessage(QtDebugMsg, "hello QFlags<MyNamespace::MyClass::MyFlags>(MyFlag1) world" ); |
1955 | MyNamespace::MyClass::MyFlags f1 = MyNamespace::MyClass::MyFlag1; |
1956 | qDebug() << "hello" << f1 << "world" ; |
1957 | |
1958 | MyNamespace::MyClass::MyFlags f2 = MyNamespace::MyClass::MyFlag2 | MyNamespace::MyClass::MyFlag3; |
1959 | QTest::ignoreMessage(QtDebugMsg, "QFlags<MyNamespace::MyClass::MyFlags>(MyFlag1) QFlags<MyNamespace::MyClass::MyFlags>(MyFlag2|MyFlag3)" ); |
1960 | qDebug() << f1 << f2; |
1961 | |
1962 | #elif QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) |
1963 | QFETCH(int, verbosity); |
1964 | |
1965 | QFETCH(QString, normalEnumMsg); |
1966 | QFETCH(QString, scopedEnumMsg); |
1967 | QFETCH(QString, globalEnumMsg); |
1968 | |
1969 | QFETCH(QString, normalFlagMsg); |
1970 | QFETCH(QString, normalFlagsMsg); |
1971 | QFETCH(QString, scopedFlagMsg); |
1972 | QFETCH(QString, scopedFlagsMsg); |
1973 | QFETCH(QString, flagAsEnumMsg); |
1974 | |
1975 | // Enums |
1976 | QTest::ignoreMessage(QtDebugMsg, qPrintable(normalEnumMsg)); |
1977 | qDebug().verbosity(verbosity) << "hello" << MyNamespace::MyClass::MyEnum2 << "world" ; |
1978 | |
1979 | QTest::ignoreMessage(QtDebugMsg, qPrintable(scopedEnumMsg)); |
1980 | qDebug().verbosity(verbosity) << "hello" << MyNamespace::MyClass::MyScopedEnum::Enum3 << "scoped world" ; |
1981 | |
1982 | QTest::ignoreMessage(QtDebugMsg, qPrintable(globalEnumMsg)); |
1983 | qDebug().verbosity(verbosity) << Qt::WindowTitleHint << Qt::Window << Qt::Desktop << Qt::WindowSystemMenuHint; |
1984 | |
1985 | // Flags |
1986 | QTest::ignoreMessage(QtDebugMsg, qPrintable(normalFlagMsg)); |
1987 | MyNamespace::MyClass::MyFlags f1 = MyNamespace::MyClass::MyFlag1; |
1988 | qDebug().verbosity(verbosity) << "hello" << f1 << "world" ; |
1989 | |
1990 | MyNamespace::MyClass::MyFlags f2 = MyNamespace::MyClass::MyFlag2 | MyNamespace::MyClass::MyFlag3; |
1991 | QTest::ignoreMessage(QtDebugMsg, qPrintable(normalFlagsMsg)); |
1992 | qDebug().verbosity(verbosity) << f1 << f2; |
1993 | |
1994 | QTest::ignoreMessage(QtDebugMsg, qPrintable(scopedFlagMsg)); |
1995 | MyNamespace::MyClass::MyScopedFlags f3 = MyNamespace::MyClass::MyScopedFlag::MyFlag2; |
1996 | qDebug().verbosity(verbosity) << f3; |
1997 | |
1998 | QTest::ignoreMessage(QtDebugMsg, qPrintable(scopedFlagsMsg)); |
1999 | f3 |= MyNamespace::MyClass::MyScopedFlag::MyFlag3; |
2000 | qDebug().verbosity(verbosity) << f3; |
2001 | |
2002 | // Single flag recognized as enum: |
2003 | QTest::ignoreMessage(QtDebugMsg, qPrintable(flagAsEnumMsg)); |
2004 | MyNamespace::MyClass::MyFlag f4 = MyNamespace::MyClass::MyFlag1; |
2005 | qDebug().verbosity(verbosity) << f4; |
2006 | #endif |
2007 | } |
2008 | |
2009 | void tst_QMetaObject::inherits_data() |
2010 | { |
2011 | QTest::addColumn<const QMetaObject *>("derivedMetaObject" ); |
2012 | QTest::addColumn<const QMetaObject *>("baseMetaObject" ); |
2013 | QTest::addColumn<bool>("inheritsResult" ); |
2014 | |
2015 | QTest::newRow("MyClass inherits QObject" ) |
2016 | << &MyNamespace::MyClass::staticMetaObject << &QObject::staticMetaObject << true; |
2017 | QTest::newRow("QObject inherits MyClass" ) |
2018 | << &QObject::staticMetaObject << &MyNamespace::MyClass::staticMetaObject << false; |
2019 | QTest::newRow("MyClass inherits MyClass" ) |
2020 | << &MyNamespace::MyClass::staticMetaObject << &MyNamespace::MyClass::staticMetaObject << true; |
2021 | QTest::newRow("MyClassSubclass inherits QObject" ) |
2022 | << &MyNamespace::MyClassSubclass::staticMetaObject << &QObject::staticMetaObject << true; |
2023 | QTest::newRow("MyClassSubclass2 inherits QObject" ) |
2024 | << &MyNamespace::MyClassSubclass2::staticMetaObject << &QObject::staticMetaObject << true; |
2025 | QTest::newRow("MyClassSubclass2 inherits MyClass2" ) |
2026 | << &MyNamespace::MyClassSubclass2::staticMetaObject << &MyNamespace::MyClass2Subclass::staticMetaObject << false; |
2027 | } |
2028 | |
2029 | void tst_QMetaObject::inherits() |
2030 | { |
2031 | #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) |
2032 | QFETCH(const QMetaObject *, derivedMetaObject); |
2033 | QFETCH(const QMetaObject *, baseMetaObject); |
2034 | QFETCH(bool, inheritsResult); |
2035 | |
2036 | QCOMPARE(derivedMetaObject->inherits(baseMetaObject), inheritsResult); |
2037 | #endif |
2038 | } |
2039 | |
2040 | void tst_QMetaObject::notifySignalsInParentClass() |
2041 | { |
2042 | #if QT_VERSION >= QT_VERSION_CHECK(5, 10, 0) |
2043 | MyNamespace::ClassWithSetterGetterSignalsAddsProperties obj; |
2044 | QCOMPARE(obj.metaObject()->property(obj.metaObject()->indexOfProperty("value1" )).notifySignal().name(), QByteArray("value1Changed" )); |
2045 | QCOMPARE(obj.metaObject()->property(obj.metaObject()->indexOfProperty("value2" )).notifySignal().name(), QByteArray("value2Changed" )); |
2046 | |
2047 | MyNamespace::ClassWithChangedSignalNewValue obj2; |
2048 | QCOMPARE(obj2.metaObject()->property(obj2.metaObject()->indexOfProperty("value2" )).notifySignal().name(), QByteArray("propertiesChanged" )); |
2049 | #if 0 // With verdigris, this is a compilation error when the NOTIFY signal is not a signal |
2050 | QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::notifySignal: cannot find the NOTIFY signal thisIsNotASignal in class MyNamespace::ClassWithChangedSignalNewValue for property 'value3'" ); |
2051 | obj2.metaObject()->property(obj2.metaObject()->indexOfProperty("value3" )).notifySignal(); |
2052 | #endif |
2053 | #endif |
2054 | } |
2055 | |
2056 | QTEST_MAIN(tst_QMetaObject) |
2057 | |