| 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 | |