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