| /**************************************************************************** |
| ** |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the test suite of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include <QtTest/QtTest> |
| #include <QtCore/qlocale.h> |
| #include <private/qmetaobjectbuilder_p.h> |
| |
| class tst_QMetaObjectBuilder : public QObject |
| { |
| Q_OBJECT |
| private slots: |
| void create(); |
| void className(); |
| void superClass(); |
| void flags(); |
| void method(); |
| void slot(); |
| void signal(); |
| void constructor(); |
| void property(); |
| void variantProperty(); |
| void notifySignal(); |
| void enumerator(); |
| void classInfo(); |
| void relatedMetaObject(); |
| void staticMetacall(); |
| void copyMetaObject(); |
| void serialize(); |
| void relocatableData(); |
| void removeNotifySignal(); |
| |
| void usage_signal(); |
| void usage_property(); |
| void usage_slot(); |
| void usage_method(); |
| void usage_constructor(); |
| void usage_connect(); |
| void usage_templateConnect(); |
| |
| void classNameFirstInStringData(); |
| |
| private: |
| static bool checkForSideEffects |
| (const QMetaObjectBuilder& builder, |
| QMetaObjectBuilder::AddMembers members); |
| static bool sameMetaObject |
| (const QMetaObject *meta1, const QMetaObject *meta2); |
| }; |
| |
| // Dummy class that has something of every type of thing moc can generate. |
| class SomethingOfEverything : public QObject |
| { |
| Q_OBJECT |
| Q_CLASSINFO("ci_foo", "ABC") |
| Q_CLASSINFO("ci_bar", "DEF") |
| Q_PROPERTY(QString prop READ prop WRITE setProp NOTIFY propChanged) |
| Q_PROPERTY(QString prop2 READ prop WRITE setProp) |
| Q_PROPERTY(QString revisionProp READ prop WRITE setProp REVISION 42) |
| Q_PROPERTY(SomethingEnum eprop READ eprop) |
| Q_PROPERTY(SomethingFlagEnum fprop READ fprop) |
| Q_PROPERTY(QLocale::Language language READ language) |
| Q_ENUMS(SomethingEnum) |
| Q_FLAGS(SomethingFlagEnum) |
| public: |
| Q_INVOKABLE SomethingOfEverything() {} |
| ~SomethingOfEverything() {} |
| |
| enum SomethingEnum |
| { |
| GHI, |
| JKL = 10 |
| }; |
| |
| enum SomethingFlagEnum |
| { |
| XYZ = 1, |
| UVW = 8 |
| }; |
| |
| Q_INVOKABLE Q_SCRIPTABLE void method1() {} |
| |
| QString prop() const { return QString(); } |
| void setProp(const QString& v) { Q_UNUSED(v); } |
| |
| SomethingOfEverything::SomethingEnum eprop() const { return GHI; } |
| SomethingOfEverything::SomethingFlagEnum fprop() const { return XYZ; } |
| QLocale::Language language() const { return QLocale::English; } |
| |
| public slots: |
| void slot1(const QString&) {} |
| void slot2(int, const QString&) {} |
| Q_REVISION(24) void revisionSlot() {} |
| |
| private slots: |
| void slot3() {} |
| |
| protected slots: |
| Q_SCRIPTABLE void slot4(int) {} |
| void slot5(int a, const QString& b) { Q_UNUSED(a); Q_UNUSED(b); } |
| |
| signals: |
| void sig1(); |
| void sig2(int x, const QString& y); |
| void propChanged(const QString&); |
| }; |
| |
| void tst_QMetaObjectBuilder::create() |
| { |
| QMetaObjectBuilder builder; |
| QVERIFY(builder.className().isEmpty()); |
| QCOMPARE(builder.superClass(), &QObject::staticMetaObject); |
| QCOMPARE(builder.methodCount(), 0); |
| QCOMPARE(builder.constructorCount(), 0); |
| QCOMPARE(builder.propertyCount(), 0); |
| QCOMPARE(builder.enumeratorCount(), 0); |
| QCOMPARE(builder.classInfoCount(), 0); |
| QCOMPARE(builder.relatedMetaObjectCount(), 0); |
| QVERIFY(!builder.staticMetacallFunction()); |
| } |
| |
| void tst_QMetaObjectBuilder::className() |
| { |
| QMetaObjectBuilder builder; |
| |
| // Change the class name. |
| builder.setClassName("Foo"); |
| QCOMPARE(builder.className(), QByteArray("Foo")); |
| |
| // Change it again. |
| builder.setClassName("Bar"); |
| QCOMPARE(builder.className(), QByteArray("Bar")); |
| |
| // Clone the class name off a static QMetaObject. |
| builder.addMetaObject(&QObject::staticMetaObject, QMetaObjectBuilder::ClassName); |
| QCOMPARE(builder.className(), QByteArray("QObject")); |
| |
| // Check that nothing else changed. |
| QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::ClassName)); |
| } |
| |
| void tst_QMetaObjectBuilder::superClass() |
| { |
| QMetaObjectBuilder builder; |
| |
| // Change the super class. |
| builder.setSuperClass(&QObject::staticMetaObject); |
| QCOMPARE(builder.superClass(), &QObject::staticMetaObject); |
| |
| // Change it again. |
| builder.setSuperClass(&staticMetaObject); |
| QCOMPARE(builder.superClass(), &staticMetaObject); |
| |
| // Clone the super class off a static QMetaObject. |
| builder.addMetaObject(&QObject::staticMetaObject, QMetaObjectBuilder::SuperClass); |
| QVERIFY(!builder.superClass()); |
| builder.addMetaObject(&staticMetaObject, QMetaObjectBuilder::SuperClass); |
| QCOMPARE(builder.superClass(), staticMetaObject.superClass()); |
| |
| // Check that nothing else changed. |
| QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::SuperClass)); |
| } |
| |
| void tst_QMetaObjectBuilder::flags() |
| { |
| QMetaObjectBuilder builder; |
| |
| // Check default |
| QCOMPARE(builder.flags(), 0); |
| |
| // Set flags |
| builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); |
| QCOMPARE(builder.flags(), QMetaObjectBuilder::DynamicMetaObject); |
| } |
| |
| void tst_QMetaObjectBuilder::method() |
| { |
| QMetaObjectBuilder builder; |
| |
| // Check null method |
| QMetaMethodBuilder nullMethod; |
| QCOMPARE(nullMethod.signature(), QByteArray()); |
| QCOMPARE(nullMethod.methodType(), QMetaMethod::Method); |
| QVERIFY(nullMethod.returnType().isEmpty()); |
| QVERIFY(nullMethod.parameterTypes().isEmpty()); |
| QVERIFY(nullMethod.parameterNames().isEmpty()); |
| QVERIFY(nullMethod.tag().isEmpty()); |
| QCOMPARE(nullMethod.access(), QMetaMethod::Public); |
| QCOMPARE(nullMethod.attributes(), 0); |
| QCOMPARE(nullMethod.revision(), 0); |
| QCOMPARE(nullMethod.index(), 0); |
| |
| // Add a method and check its attributes. |
| QMetaMethodBuilder method1 = builder.addMethod("foo(const QString&, int)"); |
| QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); |
| QCOMPARE(method1.methodType(), QMetaMethod::Method); |
| QCOMPARE(method1.returnType(), QByteArray("void")); |
| QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int"); |
| QVERIFY(method1.parameterNames().isEmpty()); |
| QVERIFY(method1.tag().isEmpty()); |
| QCOMPARE(method1.access(), QMetaMethod::Public); |
| QCOMPARE(method1.attributes(), 0); |
| QCOMPARE(method1.revision(), 0); |
| QCOMPARE(method1.index(), 0); |
| QCOMPARE(builder.methodCount(), 1); |
| |
| // Add another method and check again. |
| QMetaMethodBuilder method2 = builder.addMethod("bar(QString)", "int"); |
| QCOMPARE(method2.signature(), QByteArray("bar(QString)")); |
| QCOMPARE(method2.methodType(), QMetaMethod::Method); |
| QCOMPARE(method2.returnType(), QByteArray("int")); |
| QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString"); |
| QVERIFY(method2.parameterNames().isEmpty()); |
| QVERIFY(method2.tag().isEmpty()); |
| QCOMPARE(method2.access(), QMetaMethod::Public); |
| QCOMPARE(method2.attributes(), 0); |
| QCOMPARE(method2.revision(), 0); |
| QCOMPARE(method2.index(), 1); |
| QCOMPARE(builder.methodCount(), 2); |
| |
| // Perform index-based lookup. |
| QCOMPARE(builder.indexOfMethod("foo(const QString&, int)"), 0); |
| QCOMPARE(builder.indexOfMethod("bar(QString)"), 1); |
| QCOMPARE(builder.indexOfMethod("baz()"), -1); |
| |
| // Modify the attributes on method1. |
| method1.setReturnType("int"); |
| method1.setParameterNames(QList<QByteArray>() << "a" << "b"); |
| method1.setTag("tag"); |
| method1.setAccess(QMetaMethod::Private); |
| method1.setAttributes(42); |
| method1.setRevision(123); |
| |
| // Check that method1 is changed, but method2 is not. |
| QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); |
| QCOMPARE(method1.methodType(), QMetaMethod::Method); |
| QCOMPARE(method1.returnType(), QByteArray("int")); |
| QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int"); |
| QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b"); |
| QCOMPARE(method1.tag(), QByteArray("tag")); |
| QCOMPARE(method1.access(), QMetaMethod::Private); |
| QCOMPARE(method1.attributes(), 42); |
| QCOMPARE(method1.revision(), 123); |
| QCOMPARE(method1.index(), 0); |
| QCOMPARE(method2.signature(), QByteArray("bar(QString)")); |
| QCOMPARE(method2.methodType(), QMetaMethod::Method); |
| QCOMPARE(method2.returnType(), QByteArray("int")); |
| QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString"); |
| QVERIFY(method2.parameterNames().isEmpty()); |
| QVERIFY(method2.tag().isEmpty()); |
| QCOMPARE(method2.access(), QMetaMethod::Public); |
| QCOMPARE(method2.attributes(), 0); |
| QCOMPARE(method2.revision(), 0); |
| QCOMPARE(method2.index(), 1); |
| QCOMPARE(builder.methodCount(), 2); |
| |
| // Modify the attributes on method2. |
| method2.setReturnType("QString"); |
| method2.setParameterNames(QList<QByteArray>() << "c"); |
| method2.setTag("Q_FOO"); |
| method2.setAccess(QMetaMethod::Protected); |
| method2.setAttributes(24); |
| method2.setRevision(321); |
| |
| // This time check that only method2 changed. |
| QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); |
| QCOMPARE(method1.methodType(), QMetaMethod::Method); |
| QCOMPARE(method1.returnType(), QByteArray("int")); |
| QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int"); |
| QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b"); |
| QCOMPARE(method1.tag(), QByteArray("tag")); |
| QCOMPARE(method1.access(), QMetaMethod::Private); |
| QCOMPARE(method1.attributes(), 42); |
| QCOMPARE(method1.revision(), 123); |
| QCOMPARE(method1.index(), 0); |
| QCOMPARE(method2.signature(), QByteArray("bar(QString)")); |
| QCOMPARE(method2.methodType(), QMetaMethod::Method); |
| QCOMPARE(method2.returnType(), QByteArray("QString")); |
| QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString"); |
| QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c"); |
| QCOMPARE(method2.tag(), QByteArray("Q_FOO")); |
| QCOMPARE(method2.access(), QMetaMethod::Protected); |
| QCOMPARE(method2.attributes(), 24); |
| QCOMPARE(method2.revision(), 321); |
| QCOMPARE(method2.index(), 1); |
| QCOMPARE(builder.methodCount(), 2); |
| |
| // Remove method1 and check that method2 becomes index 0. |
| builder.removeMethod(0); |
| QCOMPARE(builder.methodCount(), 1); |
| method2 = builder.method(0); |
| QCOMPARE(method2.signature(), QByteArray("bar(QString)")); |
| QCOMPARE(method2.methodType(), QMetaMethod::Method); |
| QCOMPARE(method2.returnType(), QByteArray("QString")); |
| QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString"); |
| QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c"); |
| QCOMPARE(method2.tag(), QByteArray("Q_FOO")); |
| QCOMPARE(method2.access(), QMetaMethod::Protected); |
| QCOMPARE(method2.attributes(), 24); |
| QCOMPARE(method2.revision(), 321); |
| QCOMPARE(method2.index(), 0); |
| |
| // Perform index-based lookup again. |
| QCOMPARE(builder.indexOfMethod("foo(const QString&, int)"), -1); |
| QCOMPARE(builder.indexOfMethod("bar(QString)"), 0); |
| QCOMPARE(builder.indexOfMethod("baz()"), -1); |
| QCOMPARE(builder.method(0).signature(), QByteArray("bar(QString)")); |
| QCOMPARE(builder.method(9).signature(), QByteArray()); |
| |
| // Check that nothing else changed. |
| QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods)); |
| } |
| |
| void tst_QMetaObjectBuilder::slot() |
| { |
| QMetaObjectBuilder builder; |
| |
| // Add a slot and check its attributes. |
| QMetaMethodBuilder method1 = builder.addSlot("foo(const QString&, int)"); |
| QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); |
| QCOMPARE(method1.methodType(), QMetaMethod::Slot); |
| QCOMPARE(method1.returnType(), QByteArray("void")); |
| QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int"); |
| QVERIFY(method1.parameterNames().isEmpty()); |
| QVERIFY(method1.tag().isEmpty()); |
| QCOMPARE(method1.access(), QMetaMethod::Public); |
| QCOMPARE(method1.attributes(), 0); |
| QCOMPARE(method1.index(), 0); |
| QCOMPARE(builder.methodCount(), 1); |
| |
| // Add another slot and check again. |
| QMetaMethodBuilder method2 = builder.addSlot("bar(QString)"); |
| QCOMPARE(method2.signature(), QByteArray("bar(QString)")); |
| QCOMPARE(method2.methodType(), QMetaMethod::Slot); |
| QCOMPARE(method2.returnType(), QByteArray("void")); |
| QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString"); |
| QVERIFY(method2.parameterNames().isEmpty()); |
| QVERIFY(method2.tag().isEmpty()); |
| QCOMPARE(method2.access(), QMetaMethod::Public); |
| QCOMPARE(method2.attributes(), 0); |
| QCOMPARE(method2.index(), 1); |
| QCOMPARE(builder.methodCount(), 2); |
| |
| // Perform index-based lookup |
| QCOMPARE(builder.indexOfSlot("foo(const QString &, int)"), 0); |
| QCOMPARE(builder.indexOfSlot("bar(QString)"), 1); |
| QCOMPARE(builder.indexOfSlot("baz()"), -1); |
| |
| // Check that nothing else changed. |
| QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods)); |
| } |
| |
| void tst_QMetaObjectBuilder::signal() |
| { |
| QMetaObjectBuilder builder; |
| |
| // Add a signal and check its attributes. |
| QMetaMethodBuilder method1 = builder.addSignal("foo(const QString&, int)"); |
| QCOMPARE(method1.signature(), QByteArray("foo(QString,int)")); |
| QCOMPARE(method1.methodType(), QMetaMethod::Signal); |
| QCOMPARE(method1.returnType(), QByteArray("void")); |
| QCOMPARE(method1.parameterTypes(), QList<QByteArray>() << "QString" << "int"); |
| QVERIFY(method1.parameterNames().isEmpty()); |
| QVERIFY(method1.tag().isEmpty()); |
| QCOMPARE(method1.access(), QMetaMethod::Public); |
| QCOMPARE(method1.attributes(), 0); |
| QCOMPARE(method1.index(), 0); |
| QCOMPARE(builder.methodCount(), 1); |
| |
| // Add another signal and check again. |
| QMetaMethodBuilder method2 = builder.addSignal("bar(QString)"); |
| QCOMPARE(method2.signature(), QByteArray("bar(QString)")); |
| QCOMPARE(method2.methodType(), QMetaMethod::Signal); |
| QCOMPARE(method2.returnType(), QByteArray("void")); |
| QCOMPARE(method2.parameterTypes(), QList<QByteArray>() << "QString"); |
| QVERIFY(method2.parameterNames().isEmpty()); |
| QVERIFY(method2.tag().isEmpty()); |
| QCOMPARE(method2.access(), QMetaMethod::Public); |
| QCOMPARE(method2.attributes(), 0); |
| QCOMPARE(method2.index(), 1); |
| QCOMPARE(builder.methodCount(), 2); |
| |
| // Perform index-based lookup |
| QCOMPARE(builder.indexOfSignal("foo(const QString &, int)"), 0); |
| QCOMPARE(builder.indexOfSignal("bar(QString)"), 1); |
| QCOMPARE(builder.indexOfSignal("baz()"), -1); |
| |
| // Check that nothing else changed. |
| QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Methods)); |
| } |
| |
| void tst_QMetaObjectBuilder::constructor() |
| { |
| QMetaObjectBuilder builder; |
| |
| // Add a constructor and check its attributes. |
| QMetaMethodBuilder ctor1 = builder.addConstructor("foo(const QString&, int)"); |
| QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)")); |
| QCOMPARE(ctor1.methodType(), QMetaMethod::Constructor); |
| QVERIFY(ctor1.returnType().isEmpty()); |
| QCOMPARE(ctor1.parameterTypes(), QList<QByteArray>() << "QString" << "int"); |
| QVERIFY(ctor1.parameterNames().isEmpty()); |
| QVERIFY(ctor1.tag().isEmpty()); |
| QCOMPARE(ctor1.access(), QMetaMethod::Public); |
| QCOMPARE(ctor1.attributes(), 0); |
| QCOMPARE(ctor1.index(), 0); |
| QCOMPARE(builder.constructorCount(), 1); |
| |
| // Add another constructor and check again. |
| QMetaMethodBuilder ctor2 = builder.addConstructor("bar(QString)"); |
| QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); |
| QCOMPARE(ctor2.methodType(), QMetaMethod::Constructor); |
| QVERIFY(ctor2.returnType().isEmpty()); |
| QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString"); |
| QVERIFY(ctor2.parameterNames().isEmpty()); |
| QVERIFY(ctor2.tag().isEmpty()); |
| QCOMPARE(ctor2.access(), QMetaMethod::Public); |
| QCOMPARE(ctor2.attributes(), 0); |
| QCOMPARE(ctor2.index(), 1); |
| QCOMPARE(builder.constructorCount(), 2); |
| |
| // Perform index-based lookup. |
| QCOMPARE(builder.indexOfConstructor("foo(const QString&, int)"), 0); |
| QCOMPARE(builder.indexOfConstructor("bar(QString)"), 1); |
| QCOMPARE(builder.indexOfConstructor("baz()"), -1); |
| QCOMPARE(builder.constructor(1).signature(), QByteArray("bar(QString)")); |
| QCOMPARE(builder.constructor(9).signature(), QByteArray()); |
| |
| // Modify the attributes on ctor1. |
| ctor1.setReturnType("int"); |
| ctor1.setParameterNames(QList<QByteArray>() << "a" << "b"); |
| ctor1.setTag("tag"); |
| ctor1.setAccess(QMetaMethod::Private); |
| ctor1.setAttributes(42); |
| |
| // Check that ctor1 is changed, but ctor2 is not. |
| QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)")); |
| QCOMPARE(ctor1.methodType(), QMetaMethod::Constructor); |
| QCOMPARE(ctor1.returnType(), QByteArray("int")); |
| QCOMPARE(ctor1.parameterTypes(), QList<QByteArray>() << "QString" << "int"); |
| QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b"); |
| QCOMPARE(ctor1.tag(), QByteArray("tag")); |
| QCOMPARE(ctor1.access(), QMetaMethod::Private); |
| QCOMPARE(ctor1.attributes(), 42); |
| QCOMPARE(ctor1.index(), 0); |
| QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); |
| QCOMPARE(ctor2.methodType(), QMetaMethod::Constructor); |
| QVERIFY(ctor2.returnType().isEmpty()); |
| QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString"); |
| QVERIFY(ctor2.parameterNames().isEmpty()); |
| QVERIFY(ctor2.tag().isEmpty()); |
| QCOMPARE(ctor2.access(), QMetaMethod::Public); |
| QCOMPARE(ctor2.attributes(), 0); |
| QCOMPARE(ctor2.index(), 1); |
| QCOMPARE(builder.constructorCount(), 2); |
| |
| // Modify the attributes on ctor2. |
| ctor2.setReturnType("QString"); |
| ctor2.setParameterNames(QList<QByteArray>() << "c"); |
| ctor2.setTag("Q_FOO"); |
| ctor2.setAccess(QMetaMethod::Protected); |
| ctor2.setAttributes(24); |
| |
| // This time check that only ctor2 changed. |
| QCOMPARE(ctor1.signature(), QByteArray("foo(QString,int)")); |
| QCOMPARE(ctor1.methodType(), QMetaMethod::Constructor); |
| QCOMPARE(ctor1.returnType(), QByteArray("int")); |
| QCOMPARE(ctor1.parameterTypes(), QList<QByteArray>() << "QString" << "int"); |
| QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b"); |
| QCOMPARE(ctor1.tag(), QByteArray("tag")); |
| QCOMPARE(ctor1.access(), QMetaMethod::Private); |
| QCOMPARE(ctor1.attributes(), 42); |
| QCOMPARE(ctor1.index(), 0); |
| QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); |
| QCOMPARE(ctor2.methodType(), QMetaMethod::Constructor); |
| QCOMPARE(ctor2.returnType(), QByteArray("QString")); |
| QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString"); |
| QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c"); |
| QCOMPARE(ctor2.tag(), QByteArray("Q_FOO")); |
| QCOMPARE(ctor2.access(), QMetaMethod::Protected); |
| QCOMPARE(ctor2.attributes(), 24); |
| QCOMPARE(ctor2.index(), 1); |
| QCOMPARE(builder.constructorCount(), 2); |
| |
| // Remove ctor1 and check that ctor2 becomes index 0. |
| builder.removeConstructor(0); |
| QCOMPARE(builder.constructorCount(), 1); |
| ctor2 = builder.constructor(0); |
| QCOMPARE(ctor2.signature(), QByteArray("bar(QString)")); |
| QCOMPARE(ctor2.methodType(), QMetaMethod::Constructor); |
| QCOMPARE(ctor2.returnType(), QByteArray("QString")); |
| QCOMPARE(ctor2.parameterTypes(), QList<QByteArray>() << "QString"); |
| QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c"); |
| QCOMPARE(ctor2.tag(), QByteArray("Q_FOO")); |
| QCOMPARE(ctor2.access(), QMetaMethod::Protected); |
| QCOMPARE(ctor2.attributes(), 24); |
| QCOMPARE(ctor2.index(), 0); |
| |
| // Perform index-based lookup again. |
| QCOMPARE(builder.indexOfConstructor("foo(const QString&, int)"), -1); |
| QCOMPARE(builder.indexOfConstructor("bar(QString)"), 0); |
| QCOMPARE(builder.indexOfConstructor("baz()"), -1); |
| |
| // Add constructor from prototype |
| QMetaMethod prototype = SomethingOfEverything::staticMetaObject.constructor(0); |
| QMetaMethodBuilder prototypeConstructor = builder.addMethod(prototype); |
| QCOMPARE(builder.constructorCount(), 2); |
| |
| QCOMPARE(prototypeConstructor.signature(), QByteArray("SomethingOfEverything()")); |
| QCOMPARE(prototypeConstructor.methodType(), QMetaMethod::Constructor); |
| QCOMPARE(prototypeConstructor.returnType(), QByteArray()); |
| QVERIFY(prototypeConstructor.parameterTypes().isEmpty()); |
| QCOMPARE(prototypeConstructor.access(), QMetaMethod::Public); |
| QCOMPARE(prototypeConstructor.index(), 1); |
| |
| // Check that nothing else changed. |
| QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Constructors)); |
| } |
| |
| void tst_QMetaObjectBuilder::property() |
| { |
| QMetaObjectBuilder builder; |
| |
| // Null property builder |
| QMetaPropertyBuilder nullProp; |
| QCOMPARE(nullProp.name(), QByteArray()); |
| QCOMPARE(nullProp.type(), QByteArray()); |
| QVERIFY(!nullProp.hasNotifySignal()); |
| QVERIFY(!nullProp.isReadable()); |
| QVERIFY(!nullProp.isWritable()); |
| QVERIFY(!nullProp.isResettable()); |
| QVERIFY(!nullProp.isDesignable()); |
| QVERIFY(!nullProp.isScriptable()); |
| QVERIFY(!nullProp.isStored()); |
| QVERIFY(!nullProp.isEditable()); |
| QVERIFY(!nullProp.isUser()); |
| QVERIFY(!nullProp.hasStdCppSet()); |
| QVERIFY(!nullProp.isEnumOrFlag()); |
| QVERIFY(!nullProp.isConstant()); |
| QVERIFY(!nullProp.isFinal()); |
| QCOMPARE(nullProp.index(), 0); |
| QCOMPARE(nullProp.revision(), 0); |
| |
| // Add a property and check its attributes. |
| QMetaPropertyBuilder prop1 = builder.addProperty("foo", "const QString &"); |
| QCOMPARE(prop1.name(), QByteArray("foo")); |
| QCOMPARE(prop1.type(), QByteArray("QString")); |
| QVERIFY(!prop1.hasNotifySignal()); |
| QVERIFY(prop1.isReadable()); |
| QVERIFY(prop1.isWritable()); |
| QVERIFY(!prop1.isResettable()); |
| QVERIFY(!prop1.isDesignable()); |
| QVERIFY(prop1.isScriptable()); |
| QVERIFY(!prop1.isStored()); |
| QVERIFY(!prop1.isEditable()); |
| QVERIFY(!prop1.isUser()); |
| QVERIFY(!prop1.hasStdCppSet()); |
| QVERIFY(!prop1.isEnumOrFlag()); |
| QVERIFY(!prop1.isConstant()); |
| QVERIFY(!prop1.isFinal()); |
| QCOMPARE(prop1.revision(), 0); |
| QCOMPARE(prop1.index(), 0); |
| QCOMPARE(builder.propertyCount(), 1); |
| |
| // Add another property and check again. |
| QMetaPropertyBuilder prop2 = builder.addProperty("bar", "int"); |
| QCOMPARE(prop2.name(), QByteArray("bar")); |
| QCOMPARE(prop2.type(), QByteArray("int")); |
| QVERIFY(!prop2.hasNotifySignal()); |
| QVERIFY(prop2.isReadable()); |
| QVERIFY(prop2.isWritable()); |
| QVERIFY(!prop2.isResettable()); |
| QVERIFY(!prop2.isDesignable()); |
| QVERIFY(prop2.isScriptable()); |
| QVERIFY(!prop2.isStored()); |
| QVERIFY(!prop2.isEditable()); |
| QVERIFY(!prop2.isUser()); |
| QVERIFY(!prop2.hasStdCppSet()); |
| QVERIFY(!prop2.isEnumOrFlag()); |
| QVERIFY(!prop2.isConstant()); |
| QVERIFY(!prop2.isFinal()); |
| QCOMPARE(prop2.revision(), 0); |
| QCOMPARE(prop2.index(), 1); |
| QCOMPARE(builder.propertyCount(), 2); |
| |
| // Perform index-based lookup. |
| QCOMPARE(builder.indexOfProperty("foo"), 0); |
| QCOMPARE(builder.indexOfProperty("bar"), 1); |
| QCOMPARE(builder.indexOfProperty("baz"), -1); |
| QCOMPARE(builder.property(1).name(), QByteArray("bar")); |
| QCOMPARE(builder.property(9).name(), QByteArray()); |
| |
| // Modify the attributes on prop1. |
| prop1.setReadable(false); |
| prop1.setWritable(false); |
| prop1.setResettable(true); |
| prop1.setDesignable(true); |
| prop1.setScriptable(false); |
| prop1.setStored(true); |
| prop1.setEditable(true); |
| prop1.setUser(true); |
| prop1.setStdCppSet(true); |
| prop1.setEnumOrFlag(true); |
| prop1.setConstant(true); |
| prop1.setFinal(true); |
| prop1.setRevision(123); |
| |
| // Check that prop1 is changed, but prop2 is not. |
| QCOMPARE(prop1.name(), QByteArray("foo")); |
| QCOMPARE(prop1.type(), QByteArray("QString")); |
| QVERIFY(!prop1.isReadable()); |
| QVERIFY(!prop1.isWritable()); |
| QVERIFY(prop1.isResettable()); |
| QVERIFY(prop1.isDesignable()); |
| QVERIFY(!prop1.isScriptable()); |
| QVERIFY(prop1.isStored()); |
| QVERIFY(prop1.isEditable()); |
| QVERIFY(prop1.isUser()); |
| QVERIFY(prop1.hasStdCppSet()); |
| QVERIFY(prop1.isEnumOrFlag()); |
| QVERIFY(prop1.isConstant()); |
| QVERIFY(prop1.isFinal()); |
| QCOMPARE(prop1.revision(), 123); |
| QVERIFY(prop2.isReadable()); |
| QVERIFY(prop2.isWritable()); |
| QCOMPARE(prop2.name(), QByteArray("bar")); |
| QCOMPARE(prop2.type(), QByteArray("int")); |
| QVERIFY(!prop2.isResettable()); |
| QVERIFY(!prop2.isDesignable()); |
| QVERIFY(prop2.isScriptable()); |
| QVERIFY(!prop2.isStored()); |
| QVERIFY(!prop2.isEditable()); |
| QVERIFY(!prop2.isUser()); |
| QVERIFY(!prop2.hasStdCppSet()); |
| QVERIFY(!prop2.isEnumOrFlag()); |
| QVERIFY(!prop2.isConstant()); |
| QVERIFY(!prop2.isFinal()); |
| QCOMPARE(prop2.revision(), 0); |
| |
| // Remove prop1 and check that prop2 becomes index 0. |
| builder.removeProperty(0); |
| QCOMPARE(builder.propertyCount(), 1); |
| prop2 = builder.property(0); |
| QCOMPARE(prop2.name(), QByteArray("bar")); |
| QCOMPARE(prop2.type(), QByteArray("int")); |
| QVERIFY(!prop2.isResettable()); |
| QVERIFY(!prop2.isDesignable()); |
| QVERIFY(prop2.isScriptable()); |
| QVERIFY(!prop2.isStored()); |
| QVERIFY(!prop2.isEditable()); |
| QVERIFY(!prop2.isUser()); |
| QVERIFY(!prop2.hasStdCppSet()); |
| QVERIFY(!prop2.isEnumOrFlag()); |
| QVERIFY(!prop2.isConstant()); |
| QVERIFY(!prop2.isFinal()); |
| QCOMPARE(prop2.revision(), 0); |
| QCOMPARE(prop2.index(), 0); |
| |
| // Perform index-based lookup again. |
| QCOMPARE(builder.indexOfProperty("foo"), -1); |
| QCOMPARE(builder.indexOfProperty("bar"), 0); |
| QCOMPARE(builder.indexOfProperty("baz"), -1); |
| |
| // Check for side-effects between the flags on prop2. |
| // Setting a flag to true shouldn't set any of the others to true. |
| // This checks for cut-and-paste bugs in the implementation where |
| // the flag code was pasted but the flag name was not changed. |
| #define CLEAR_FLAGS() \ |
| do { \ |
| prop2.setReadable(false); \ |
| prop2.setWritable(false); \ |
| prop2.setResettable(false); \ |
| prop2.setDesignable(false); \ |
| prop2.setScriptable(false); \ |
| prop2.setStored(false); \ |
| prop2.setEditable(false); \ |
| prop2.setUser(false); \ |
| prop2.setStdCppSet(false); \ |
| prop2.setEnumOrFlag(false); \ |
| prop2.setConstant(false); \ |
| prop2.setFinal(false); \ |
| } while (0) |
| #define COUNT_FLAGS() \ |
| ((prop2.isReadable() ? 1 : 0) + \ |
| (prop2.isWritable() ? 1 : 0) + \ |
| (prop2.isResettable() ? 1 : 0) + \ |
| (prop2.isDesignable() ? 1 : 0) + \ |
| (prop2.isScriptable() ? 1 : 0) + \ |
| (prop2.isStored() ? 1 : 0) + \ |
| (prop2.isEditable() ? 1 : 0) + \ |
| (prop2.isUser() ? 1 : 0) + \ |
| (prop2.hasStdCppSet() ? 1 : 0) + \ |
| (prop2.isEnumOrFlag() ? 1 : 0) + \ |
| (prop2.isConstant() ? 1 : 0) + \ |
| (prop2.isFinal() ? 1 : 0)) |
| #define CHECK_FLAG(setFunc,isFunc) \ |
| do { \ |
| CLEAR_FLAGS(); \ |
| QCOMPARE(COUNT_FLAGS(), 0); \ |
| prop2.setFunc(true); \ |
| QVERIFY(prop2.isFunc()); \ |
| QCOMPARE(COUNT_FLAGS(), 1); \ |
| } while (0) |
| CHECK_FLAG(setReadable, isReadable); |
| CHECK_FLAG(setWritable, isWritable); |
| CHECK_FLAG(setResettable, isResettable); |
| CHECK_FLAG(setDesignable, isDesignable); |
| CHECK_FLAG(setScriptable, isScriptable); |
| CHECK_FLAG(setStored, isStored); |
| CHECK_FLAG(setEditable, isEditable); |
| CHECK_FLAG(setUser, isUser); |
| CHECK_FLAG(setStdCppSet, hasStdCppSet); |
| CHECK_FLAG(setEnumOrFlag, isEnumOrFlag); |
| CHECK_FLAG(setConstant, isConstant); |
| CHECK_FLAG(setFinal, isFinal); |
| |
| // Check that nothing else changed. |
| QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Properties)); |
| |
| // Add property from prototype |
| QMetaProperty prototype = SomethingOfEverything::staticMetaObject.property(1); |
| QVERIFY(prototype.name() == QByteArray("prop")); |
| QMetaPropertyBuilder prototypeProp = builder.addProperty(prototype); |
| QCOMPARE(prototypeProp.name(), QByteArray("prop")); |
| QVERIFY(prototypeProp.hasNotifySignal()); |
| QCOMPARE(prototypeProp.notifySignal().signature(), QByteArray("propChanged(QString)")); |
| QCOMPARE(builder.methodCount(), 1); |
| QCOMPARE(builder.method(0).signature(), QByteArray("propChanged(QString)")); |
| } |
| |
| void tst_QMetaObjectBuilder::variantProperty() |
| { |
| QMetaObjectBuilder builder; |
| builder.addProperty("variant", "const QVariant &"); |
| QMetaObject *meta = builder.toMetaObject(); |
| |
| QMetaProperty prop = meta->property(meta->propertyOffset()); |
| QCOMPARE(QMetaType::Type(prop.type()), QMetaType::QVariant); |
| QCOMPARE(QMetaType::Type(prop.userType()), QMetaType::QVariant); |
| QCOMPARE(QByteArray(prop.typeName()), QByteArray("QVariant")); |
| |
| free(meta); |
| } |
| |
| void tst_QMetaObjectBuilder::notifySignal() |
| { |
| QMetaObjectBuilder builder; |
| |
| QMetaPropertyBuilder prop = builder.addProperty("foo", "const QString &"); |
| builder.addSlot("setFoo(QString)"); |
| QMetaMethodBuilder notify = builder.addSignal("fooChanged(QString)"); |
| |
| QVERIFY(!prop.hasNotifySignal()); |
| QCOMPARE(prop.notifySignal().index(), 0); |
| |
| prop.setNotifySignal(notify); |
| QVERIFY(prop.hasNotifySignal()); |
| QCOMPARE(prop.notifySignal().index(), 1); |
| |
| prop.setNotifySignal(QMetaMethodBuilder()); |
| QVERIFY(!prop.hasNotifySignal()); |
| QCOMPARE(prop.notifySignal().index(), 0); |
| |
| prop.setNotifySignal(notify); |
| prop.removeNotifySignal(); |
| QVERIFY(!prop.hasNotifySignal()); |
| QCOMPARE(prop.notifySignal().index(), 0); |
| |
| QCOMPARE(builder.methodCount(), 2); |
| QCOMPARE(builder.propertyCount(), 1); |
| |
| // Check that nothing else changed except methods and properties. |
| QVERIFY(checkForSideEffects |
| (builder, QMetaObjectBuilder::Methods | QMetaObjectBuilder::Properties)); |
| } |
| |
| void tst_QMetaObjectBuilder::enumerator() |
| { |
| QMetaObjectBuilder builder; |
| |
| // Add an enumerator and check its attributes. |
| QMetaEnumBuilder enum1 = builder.addEnumerator("foo"); |
| QCOMPARE(enum1.name(), QByteArray("foo")); |
| QVERIFY(!enum1.isFlag()); |
| QVERIFY(!enum1.isScoped()); |
| QCOMPARE(enum1.keyCount(), 0); |
| QCOMPARE(enum1.index(), 0); |
| QCOMPARE(builder.enumeratorCount(), 1); |
| |
| // Add another enumerator and check again. |
| QMetaEnumBuilder enum2 = builder.addEnumerator("bar"); |
| QCOMPARE(enum2.name(), QByteArray("bar")); |
| QVERIFY(!enum2.isFlag()); |
| QVERIFY(!enum2.isScoped()); |
| QCOMPARE(enum2.keyCount(), 0); |
| QCOMPARE(enum2.index(), 1); |
| QCOMPARE(builder.enumeratorCount(), 2); |
| |
| // Perform index-based lookup. |
| QCOMPARE(builder.indexOfEnumerator("foo"), 0); |
| QCOMPARE(builder.indexOfEnumerator("bar"), 1); |
| QCOMPARE(builder.indexOfEnumerator("baz"), -1); |
| QCOMPARE(builder.enumerator(1).name(), QByteArray("bar")); |
| QCOMPARE(builder.enumerator(9).name(), QByteArray()); |
| |
| // Modify the attributes on enum1. |
| enum1.setIsFlag(true); |
| enum1.setIsScoped(true); |
| enum1.setEnumName(QByteArrayLiteral("fooFlag")); |
| QCOMPARE(enum1.addKey("ABC", 0), 0); |
| QCOMPARE(enum1.addKey("DEF", 1), 1); |
| QCOMPARE(enum1.addKey("GHI", -1), 2); |
| |
| // Check that enum1 is changed, but enum2 is not. |
| QCOMPARE(enum1.name(), QByteArray("foo")); |
| QVERIFY(enum1.isFlag()); |
| QVERIFY(enum1.isScoped()); |
| QCOMPARE(enum1.enumName(), QByteArray("fooFlag")); |
| QCOMPARE(enum1.keyCount(), 3); |
| QCOMPARE(enum1.index(), 0); |
| QCOMPARE(enum1.key(0), QByteArray("ABC")); |
| QCOMPARE(enum1.key(1), QByteArray("DEF")); |
| QCOMPARE(enum1.key(2), QByteArray("GHI")); |
| QCOMPARE(enum1.key(3), QByteArray()); |
| QCOMPARE(enum1.value(0), 0); |
| QCOMPARE(enum1.value(1), 1); |
| QCOMPARE(enum1.value(2), -1); |
| QCOMPARE(enum2.name(), QByteArray("bar")); |
| QVERIFY(!enum2.isFlag()); |
| QVERIFY(!enum2.isScoped()); |
| QCOMPARE(enum2.keyCount(), 0); |
| QCOMPARE(enum2.index(), 1); |
| |
| // Modify the attributes on enum2. |
| enum2.setIsFlag(true); |
| QCOMPARE(enum2.addKey("XYZ", 10), 0); |
| QCOMPARE(enum2.addKey("UVW", 19), 1); |
| |
| // This time check that only method2 changed. |
| QCOMPARE(enum1.name(), QByteArray("foo")); |
| QVERIFY(enum1.isFlag()); |
| QVERIFY(enum1.isScoped()); |
| QCOMPARE(enum1.keyCount(), 3); |
| QCOMPARE(enum1.index(), 0); |
| QCOMPARE(enum1.key(0), QByteArray("ABC")); |
| QCOMPARE(enum1.key(1), QByteArray("DEF")); |
| QCOMPARE(enum1.key(2), QByteArray("GHI")); |
| QCOMPARE(enum1.key(3), QByteArray()); |
| QCOMPARE(enum1.value(0), 0); |
| QCOMPARE(enum1.value(1), 1); |
| QCOMPARE(enum1.value(2), -1); |
| QCOMPARE(enum2.name(), QByteArray("bar")); |
| QVERIFY(enum2.isFlag()); |
| QVERIFY(!enum2.isScoped()); |
| QCOMPARE(enum2.keyCount(), 2); |
| QCOMPARE(enum2.index(), 1); |
| QCOMPARE(enum2.key(0), QByteArray("XYZ")); |
| QCOMPARE(enum2.key(1), QByteArray("UVW")); |
| QCOMPARE(enum2.key(2), QByteArray()); |
| QCOMPARE(enum2.value(0), 10); |
| QCOMPARE(enum2.value(1), 19); |
| |
| // Remove enum1 key |
| enum1.removeKey(2); |
| QCOMPARE(enum1.name(), QByteArray("foo")); |
| QVERIFY(enum1.isFlag()); |
| QVERIFY(enum1.isScoped()); |
| QCOMPARE(enum1.keyCount(), 2); |
| QCOMPARE(enum1.index(), 0); |
| QCOMPARE(enum1.key(0), QByteArray("ABC")); |
| QCOMPARE(enum1.key(1), QByteArray("DEF")); |
| QCOMPARE(enum1.key(2), QByteArray()); |
| QCOMPARE(enum1.value(0), 0); |
| QCOMPARE(enum1.value(1), 1); |
| QCOMPARE(enum1.value(2), -1); |
| QCOMPARE(enum2.name(), QByteArray("bar")); |
| QVERIFY(enum2.isFlag()); |
| QVERIFY(!enum2.isScoped()); |
| QCOMPARE(enum2.keyCount(), 2); |
| QCOMPARE(enum2.index(), 1); |
| QCOMPARE(enum2.key(0), QByteArray("XYZ")); |
| QCOMPARE(enum2.key(1), QByteArray("UVW")); |
| QCOMPARE(enum2.key(2), QByteArray()); |
| QCOMPARE(enum2.value(0), 10); |
| QCOMPARE(enum2.value(1), 19); |
| |
| // Remove enum1 and check that enum2 becomes index 0. |
| builder.removeEnumerator(0); |
| QCOMPARE(builder.enumeratorCount(), 1); |
| enum2 = builder.enumerator(0); |
| QCOMPARE(enum2.name(), QByteArray("bar")); |
| QVERIFY(enum2.isFlag()); |
| QVERIFY(!enum2.isScoped()); |
| QCOMPARE(enum2.keyCount(), 2); |
| QCOMPARE(enum2.index(), 0); |
| QCOMPARE(enum2.key(0), QByteArray("XYZ")); |
| QCOMPARE(enum2.key(1), QByteArray("UVW")); |
| QCOMPARE(enum2.key(2), QByteArray()); |
| QCOMPARE(enum2.value(0), 10); |
| QCOMPARE(enum2.value(1), 19); |
| |
| // Perform index-based lookup again. |
| QCOMPARE(builder.indexOfEnumerator("foo"), -1); |
| QCOMPARE(builder.indexOfEnumerator("bar"), 0); |
| QCOMPARE(builder.indexOfEnumerator("baz"), -1); |
| |
| // Check that nothing else changed. |
| QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Enumerators)); |
| } |
| |
| void tst_QMetaObjectBuilder::classInfo() |
| { |
| QMetaObjectBuilder builder; |
| |
| // Add two items of class information and check their attributes. |
| QCOMPARE(builder.addClassInfo("foo", "value1"), 0); |
| QCOMPARE(builder.addClassInfo("bar", "value2"), 1); |
| QCOMPARE(builder.classInfoName(0), QByteArray("foo")); |
| QCOMPARE(builder.classInfoValue(0), QByteArray("value1")); |
| QCOMPARE(builder.classInfoName(1), QByteArray("bar")); |
| QCOMPARE(builder.classInfoValue(1), QByteArray("value2")); |
| QCOMPARE(builder.classInfoName(9), QByteArray()); |
| QCOMPARE(builder.classInfoValue(9), QByteArray()); |
| QCOMPARE(builder.classInfoCount(), 2); |
| |
| // Perform index-based lookup. |
| QCOMPARE(builder.indexOfClassInfo("foo"), 0); |
| QCOMPARE(builder.indexOfClassInfo("bar"), 1); |
| QCOMPARE(builder.indexOfClassInfo("baz"), -1); |
| |
| // Remove the first one and check again. |
| builder.removeClassInfo(0); |
| QCOMPARE(builder.classInfoName(0), QByteArray("bar")); |
| QCOMPARE(builder.classInfoValue(0), QByteArray("value2")); |
| QCOMPARE(builder.classInfoCount(), 1); |
| |
| // Perform index-based lookup again. |
| QCOMPARE(builder.indexOfClassInfo("foo"), -1); |
| QCOMPARE(builder.indexOfClassInfo("bar"), 0); |
| QCOMPARE(builder.indexOfClassInfo("baz"), -1); |
| |
| // Check that nothing else changed. |
| QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::ClassInfos)); |
| } |
| |
| void tst_QMetaObjectBuilder::relatedMetaObject() |
| { |
| QMetaObjectBuilder builder; |
| |
| // Add two related meta objects and check their attributes. |
| QCOMPARE(builder.addRelatedMetaObject(&QObject::staticMetaObject), 0); |
| QCOMPARE(builder.addRelatedMetaObject(&staticMetaObject), 1); |
| QCOMPARE(builder.relatedMetaObject(0), &QObject::staticMetaObject); |
| QCOMPARE(builder.relatedMetaObject(1), &staticMetaObject); |
| QCOMPARE(builder.relatedMetaObjectCount(), 2); |
| |
| // Remove the first one and check again. |
| builder.removeRelatedMetaObject(0); |
| QCOMPARE(builder.relatedMetaObject(0), &staticMetaObject); |
| QCOMPARE(builder.relatedMetaObjectCount(), 1); |
| |
| // Check that nothing else changed. |
| QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::RelatedMetaObjects)); |
| } |
| |
| static void smetacall(QObject *, QMetaObject::Call, int, void **) |
| { |
| return; |
| } |
| |
| void tst_QMetaObjectBuilder::staticMetacall() |
| { |
| QMetaObjectBuilder builder; |
| QVERIFY(!builder.staticMetacallFunction()); |
| builder.setStaticMetacallFunction(smetacall); |
| QVERIFY(builder.staticMetacallFunction() == smetacall); |
| QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::StaticMetacall)); |
| } |
| |
| // Copy the entire contents of a static QMetaObject and then check |
| // that QMetaObjectBuilder will produce an exact copy as output. |
| void tst_QMetaObjectBuilder::copyMetaObject() |
| { |
| QMetaObjectBuilder builder(&QObject::staticMetaObject); |
| QMetaObject *meta = builder.toMetaObject(); |
| QVERIFY(sameMetaObject(meta, &QObject::staticMetaObject)); |
| free(meta); |
| |
| QMetaObjectBuilder builder2(&staticMetaObject); |
| meta = builder2.toMetaObject(); |
| QVERIFY(sameMetaObject(meta, &staticMetaObject)); |
| free(meta); |
| |
| QMetaObjectBuilder builder3(&SomethingOfEverything::staticMetaObject); |
| meta = builder3.toMetaObject(); |
| QVERIFY(sameMetaObject(meta, &SomethingOfEverything::staticMetaObject)); |
| free(meta); |
| } |
| |
| // Serialize and deserialize a meta object and check that |
| // it round-trips to the exact same value. |
| void tst_QMetaObjectBuilder::serialize() |
| { |
| // Full QMetaObjectBuilder |
| { |
| QMetaObjectBuilder builder(&SomethingOfEverything::staticMetaObject); |
| QMetaObject *meta = builder.toMetaObject(); |
| |
| QByteArray data; |
| QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append); |
| builder.serialize(stream); |
| |
| QMetaObjectBuilder builder2; |
| QDataStream stream2(data); |
| QMap<QByteArray, const QMetaObject *> references; |
| references.insert(QByteArray("QLocale"), &QLocale::staticMetaObject); |
| builder2.deserialize(stream2, references); |
| builder2.setStaticMetacallFunction(builder.staticMetacallFunction()); |
| QMetaObject *meta2 = builder2.toMetaObject(); |
| |
| QVERIFY(sameMetaObject(meta, meta2)); |
| free(meta); |
| free(meta2); |
| } |
| |
| // Partial QMetaObjectBuilder |
| { |
| QMetaObjectBuilder builder; |
| builder.setClassName("Test"); |
| builder.addProperty("foo", "int"); |
| |
| QByteArray data; |
| QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append); |
| builder.serialize(stream); |
| |
| QMetaObjectBuilder builder2; |
| QDataStream stream2(data); |
| builder2.deserialize(stream2, QMap<QByteArray, const QMetaObject *>()); |
| |
| QCOMPARE(builder.superClass(), builder2.superClass()); |
| QCOMPARE(builder.className(), builder2.className()); |
| QCOMPARE(builder.propertyCount(), builder2.propertyCount()); |
| QCOMPARE(builder.property(0).name(), builder2.property(0).name()); |
| QCOMPARE(builder.property(0).type(), builder2.property(0).type()); |
| } |
| } |
| |
| void tst_QMetaObjectBuilder::relocatableData() |
| { |
| QMetaObjectBuilder builder; |
| builder.setClassName("TestObject"); |
| |
| QMetaMethodBuilder intPropChanged = builder.addSignal("intPropChanged(int)"); |
| intPropChanged.setParameterNames(QList<QByteArray>() << "newIntPropValue"); |
| |
| QMetaPropertyBuilder prop = builder.addProperty("intProp", "int"); |
| prop.setNotifySignal(intPropChanged); |
| |
| QMetaMethodBuilder voidSlotInt = builder.addSlot("voidSlotInt(int)"); |
| voidSlotInt.setParameterNames(QList<QByteArray>() << "slotIntArg"); |
| |
| QMetaMethodBuilder listInvokableQRealQString = builder.addMethod("listInvokableQRealQString(qreal,QString)"); |
| listInvokableQRealQString.setReturnType("QVariantList"); |
| listInvokableQRealQString.setParameterNames(QList<QByteArray>() << "qrealArg" << "qstringArg"); |
| |
| bool ok = false; |
| QByteArray data = builder.toRelocatableData(&ok); |
| QVERIFY(ok); |
| |
| QMetaObjectBuilder builder2; |
| QMetaObject meta2; |
| builder2.fromRelocatableData(&meta2, &QObject::staticMetaObject, data); |
| |
| QMetaObject *meta = builder.toMetaObject(); |
| |
| QVERIFY(sameMetaObject(meta, &meta2)); |
| |
| QVERIFY(!meta2.d.extradata); |
| QVERIFY(!meta2.d.relatedMetaObjects); |
| QVERIFY(!meta2.d.static_metacall); |
| |
| free(meta); |
| } |
| |
| |
| // Check that removing a method updates notify signals appropriately |
| void tst_QMetaObjectBuilder::removeNotifySignal() |
| { |
| QMetaObjectBuilder builder; |
| |
| builder.addSignal("foo(const QString&, int)"); |
| QMetaMethodBuilder method = builder.addSignal("bar(QString)"); |
| |
| // Setup property |
| QMetaPropertyBuilder prop = builder.addProperty("prop", "const QString &"); |
| prop.setNotifySignal(method); |
| QVERIFY(prop.hasNotifySignal()); |
| QCOMPARE(prop.notifySignal().index(), 1); |
| |
| // Remove non-notify signal |
| builder.removeMethod(0); |
| QVERIFY(prop.hasNotifySignal()); |
| QCOMPARE(prop.notifySignal().index(), 0); |
| |
| // Remove notify signal |
| builder.removeMethod(0); |
| QVERIFY(!prop.hasNotifySignal()); |
| } |
| |
| // Check that the only changes to a "builder" relative to the default |
| // state is specified by "members". |
| bool tst_QMetaObjectBuilder::checkForSideEffects |
| (const QMetaObjectBuilder& builder, |
| QMetaObjectBuilder::AddMembers members) |
| { |
| if ((members & QMetaObjectBuilder::ClassName) == 0) { |
| if (!builder.className().isEmpty()) |
| return false; |
| } |
| |
| if ((members & QMetaObjectBuilder::SuperClass) == 0) { |
| if (builder.superClass() != &QObject::staticMetaObject) |
| return false; |
| } |
| |
| if ((members & QMetaObjectBuilder::Methods) == 0) { |
| if (builder.methodCount() != 0) |
| return false; |
| } |
| |
| if ((members & QMetaObjectBuilder::Constructors) == 0) { |
| if (builder.constructorCount() != 0) |
| return false; |
| } |
| |
| if ((members & QMetaObjectBuilder::Properties) == 0) { |
| if (builder.propertyCount() != 0) |
| return false; |
| } |
| |
| if ((members & QMetaObjectBuilder::Enumerators) == 0) { |
| if (builder.enumeratorCount() != 0) |
| return false; |
| } |
| |
| if ((members & QMetaObjectBuilder::ClassInfos) == 0) { |
| if (builder.classInfoCount() != 0) |
| return false; |
| } |
| |
| if ((members & QMetaObjectBuilder::RelatedMetaObjects) == 0) { |
| if (builder.relatedMetaObjectCount() != 0) |
| return false; |
| } |
| |
| if ((members & QMetaObjectBuilder::StaticMetacall) == 0) { |
| if (builder.staticMetacallFunction() != 0) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| static bool sameMethod(const QMetaMethod& method1, const QMetaMethod& method2) |
| { |
| if (method1.methodSignature() != method2.methodSignature()) |
| return false; |
| |
| if (QByteArray(method1.typeName()) != QByteArray(method2.typeName())) |
| return false; |
| |
| if (method1.parameterTypes() != method2.parameterTypes()) |
| return false; |
| |
| if (method1.parameterNames() != method2.parameterNames()) |
| return false; |
| |
| if (QByteArray(method1.tag()) != QByteArray(method2.tag())) |
| return false; |
| |
| if (method1.access() != method2.access()) |
| return false; |
| |
| if (method1.methodType() != method2.methodType()) |
| return false; |
| |
| if (method1.attributes() != method2.attributes()) |
| return false; |
| |
| if (method1.revision() != method2.revision()) |
| return false; |
| |
| return true; |
| } |
| |
| static bool sameProperty(const QMetaProperty& prop1, const QMetaProperty& prop2) |
| { |
| if (QByteArray(prop1.name()) != QByteArray(prop2.name())) |
| return false; |
| |
| if (QByteArray(prop1.typeName()) != QByteArray(prop2.typeName())) |
| return false; |
| |
| if (prop1.isReadable() != prop2.isReadable() || |
| prop1.isWritable() != prop2.isWritable() || |
| prop1.isResettable() != prop2.isResettable() || |
| prop1.isDesignable() != prop2.isDesignable() || |
| prop1.isScriptable() != prop2.isScriptable() || |
| prop1.isStored() != prop2.isStored() || |
| prop1.isEditable() != prop2.isEditable() || |
| prop1.isUser() != prop2.isUser() || |
| prop1.isFlagType() != prop2.isFlagType() || |
| prop1.isEnumType() != prop2.isEnumType() || |
| prop1.hasNotifySignal() != prop2.hasNotifySignal() || |
| prop1.hasStdCppSet() != prop2.hasStdCppSet()) |
| return false; |
| |
| if (prop1.hasNotifySignal()) { |
| if (prop1.notifySignalIndex() != prop2.notifySignalIndex()) |
| return false; |
| } |
| |
| if (prop1.revision() != prop2.revision()) |
| return false; |
| |
| return true; |
| } |
| |
| static bool sameEnumerator(const QMetaEnum& enum1, const QMetaEnum& enum2) |
| { |
| if (QByteArray(enum1.name()) != QByteArray(enum2.name())) |
| return false; |
| |
| if (enum1.isFlag() != enum2.isFlag()) |
| return false; |
| |
| if (enum1.keyCount() != enum2.keyCount()) |
| return false; |
| |
| for (int index = 0; index < enum1.keyCount(); ++index) { |
| if (QByteArray(enum1.key(index)) != QByteArray(enum2.key(index))) |
| return false; |
| if (enum1.value(index) != enum2.value(index)) |
| return false; |
| } |
| |
| if (QByteArray(enum1.scope()) != QByteArray(enum2.scope())) |
| return false; |
| |
| return true; |
| } |
| |
| // Determine if two meta objects are identical. |
| bool tst_QMetaObjectBuilder::sameMetaObject |
| (const QMetaObject *meta1, const QMetaObject *meta2) |
| { |
| int index; |
| |
| if (strcmp(meta1->className(), meta2->className()) != 0) |
| return false; |
| |
| if (meta1->superClass() != meta2->superClass()) |
| return false; |
| |
| if (meta1->constructorCount() != meta2->constructorCount() || |
| meta1->methodCount() != meta2->methodCount() || |
| meta1->enumeratorCount() != meta2->enumeratorCount() || |
| meta1->propertyCount() != meta2->propertyCount() || |
| meta1->classInfoCount() != meta2->classInfoCount()) |
| return false; |
| |
| for (index = 0; index < meta1->constructorCount(); ++index) { |
| if (!sameMethod(meta1->constructor(index), meta2->constructor(index))) |
| return false; |
| } |
| |
| for (index = 0; index < meta1->methodCount(); ++index) { |
| if (!sameMethod(meta1->method(index), meta2->method(index))) |
| return false; |
| } |
| |
| for (index = 0; index < meta1->propertyCount(); ++index) { |
| if (!sameProperty(meta1->property(index), meta2->property(index))) |
| return false; |
| } |
| |
| for (index = 0; index < meta1->enumeratorCount(); ++index) { |
| if (!sameEnumerator(meta1->enumerator(index), meta2->enumerator(index))) |
| return false; |
| } |
| |
| for (index = 0; index < meta1->classInfoCount(); ++index) { |
| if (QByteArray(meta1->classInfo(index).name()) != |
| QByteArray(meta2->classInfo(index).name())) |
| return false; |
| if (QByteArray(meta1->classInfo(index).value()) != |
| QByteArray(meta2->classInfo(index).value())) |
| return false; |
| } |
| |
| const auto *objects1 = meta1->d.relatedMetaObjects; |
| const auto *objects2 = meta2->d.relatedMetaObjects; |
| if (objects1 && !objects2) |
| return false; |
| if (objects2 && !objects1) |
| return false; |
| if (objects1 && objects2) { |
| while (*objects1 != 0 && *objects2 != 0) { |
| if (*objects1 != *objects2) |
| return false; |
| ++objects1; |
| ++objects2; |
| } |
| } |
| |
| return true; |
| } |
| |
| |
| // This class is used to test that the meta-object generated by QMOB can be |
| // used by a real object. |
| // The class manually implements the functions normally generated by moc, and |
| // creates the corresponding meta-object using QMOB. The autotests check that |
| // this object can be used by QObject/QMetaObject functionality (property |
| // access, signals & slots, constructing instances, ...). |
| |
| class TestObject : public QObject |
| { |
| // Manually expanded from Q_OBJECT macro |
| public: |
| Q_OBJECT_CHECK |
| static QMetaObject staticMetaObject; |
| virtual const QMetaObject *metaObject() const; |
| virtual void *qt_metacast(const char *); |
| virtual int qt_metacall(QMetaObject::Call, int, void **); |
| private: |
| Q_DECL_HIDDEN static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **); |
| |
| //Q_PROPERTY(int intProp READ intProp WRITE setIntProp NOTIFY intPropChanged) |
| public: |
| TestObject(QObject *parent = 0); // Q_INVOKABLE |
| ~TestObject(); |
| |
| // Property accessors |
| int intProp() const; |
| void setIntProp(int v); |
| |
| void emitIntPropChanged(); |
| |
| int voidSlotIntArgument() const; |
| |
| // Q_INVOKABLE |
| QVariantList listInvokableQRealQString(qreal, const QString &); |
| |
| //public Q_SLOTS: |
| void voidSlotInt(int); |
| |
| //Q_SIGNALS: |
| void intPropChanged(int); |
| |
| private: |
| static QMetaObject *buildMetaObject(); |
| |
| QMetaObject *m_metaObject; |
| int m_intProp; |
| int m_voidSlotIntArg; |
| }; |
| |
| QMetaObject TestObject::staticMetaObject = { |
| { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr } |
| }; |
| |
| TestObject::TestObject(QObject *parent) |
| : QObject(parent), m_metaObject(buildMetaObject()), |
| m_intProp(-1), m_voidSlotIntArg(-1) |
| { |
| staticMetaObject = *m_metaObject; |
| } |
| |
| TestObject::~TestObject() |
| { |
| free(m_metaObject); |
| } |
| |
| QMetaObject *TestObject::buildMetaObject() |
| { |
| QMetaObjectBuilder builder; |
| // NOTE: If you change the meta-object, remember to adapt qt_metacall and |
| // friends below accordingly. |
| |
| builder.setClassName("TestObject"); |
| |
| builder.setStaticMetacallFunction(qt_static_metacall); |
| |
| QMetaMethodBuilder intPropChanged = builder.addSignal("intPropChanged(int)"); |
| intPropChanged.setParameterNames(QList<QByteArray>() << "newIntPropValue"); |
| |
| QMetaPropertyBuilder prop = builder.addProperty("intProp", "int"); |
| prop.setNotifySignal(intPropChanged); |
| |
| QMetaMethodBuilder voidSlotInt = builder.addSlot("voidSlotInt(int)"); |
| voidSlotInt.setParameterNames(QList<QByteArray>() << "slotIntArg"); |
| |
| QMetaMethodBuilder listInvokableQRealQString = builder.addMethod("listInvokableQRealQString(qreal,QString)"); |
| listInvokableQRealQString.setReturnType("QVariantList"); |
| listInvokableQRealQString.setParameterNames(QList<QByteArray>() << "qrealArg" << "qstringArg"); |
| |
| builder.addConstructor("TestObject(QObject*)"); |
| builder.addConstructor("TestObject()"); |
| |
| return builder.toMetaObject(); |
| } |
| |
| int TestObject::intProp() const |
| { |
| return m_intProp; |
| } |
| |
| void TestObject::setIntProp(int value) |
| { |
| if (m_intProp != value) { |
| m_intProp = value; |
| emit intPropChanged(value); |
| } |
| } |
| |
| void TestObject::emitIntPropChanged() |
| { |
| emit intPropChanged(m_intProp); |
| } |
| |
| QVariantList TestObject::listInvokableQRealQString(qreal r, const QString &s) |
| { |
| return QVariantList() << r << s; |
| } |
| |
| void TestObject::voidSlotInt(int value) |
| { |
| m_voidSlotIntArg = value; |
| } |
| |
| int TestObject::voidSlotIntArgument() const |
| { |
| return m_voidSlotIntArg; |
| } |
| |
| void TestObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a) |
| { |
| if (_c == QMetaObject::CreateInstance) { |
| switch (_id) { |
| case 0: { TestObject *_r = new TestObject((*reinterpret_cast< QObject*(*)>(_a[1]))); |
| if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break; |
| case 1: { TestObject *_r = new TestObject(); |
| if (_a[0]) *reinterpret_cast<QObject**>(_a[0]) = _r; } break; |
| default: { |
| QMetaMethod ctor = _o->metaObject()->constructor(_id); |
| qFatal("You forgot to add a case for CreateInstance %s", ctor.methodSignature().constData()); |
| } |
| } |
| } else if (_c == QMetaObject::InvokeMetaMethod) { |
| Q_ASSERT(_o->metaObject()->cast(_o)); |
| TestObject *_t = static_cast<TestObject *>(_o); |
| switch (_id) { |
| case 0: _t->intPropChanged((*reinterpret_cast< int(*)>(_a[1]))); break; |
| case 1: _t->voidSlotInt((*reinterpret_cast< int(*)>(_a[1]))); break; |
| case 2: *reinterpret_cast<QVariantList(*)>(_a[0]) = _t->listInvokableQRealQString(*reinterpret_cast<qreal(*)>(_a[1]), *reinterpret_cast<QString(*)>(_a[2])); break; |
| default: { |
| QMetaMethod method = _o->metaObject()->method(_o->metaObject()->methodOffset() + _id); |
| qFatal("You forgot to add a case for InvokeMetaMethod %s", method.methodSignature().constData()); |
| } |
| } |
| } else if (_c == QMetaObject::IndexOfMethod) { |
| int *result = reinterpret_cast<int *>(_a[0]); |
| void **func = reinterpret_cast<void **>(_a[1]); |
| { |
| typedef void (TestObject::*_t)(int ); |
| if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestObject::intPropChanged)) { |
| *result = 0; |
| } |
| } |
| { |
| typedef void (TestObject::*_t)(int ); |
| if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestObject::voidSlotInt)) { |
| *result = 1; |
| } |
| } |
| { |
| typedef QVariantList (TestObject::*_t)(qreal, const QString &); |
| if (*reinterpret_cast<_t *>(func) == static_cast<_t>(&TestObject::listInvokableQRealQString)) { |
| *result = 2; |
| } |
| } |
| } |
| } |
| |
| const QMetaObject *TestObject::metaObject() const |
| { |
| return m_metaObject; |
| } |
| |
| void *TestObject::qt_metacast(const char *_clname) |
| { |
| if (!_clname) return 0; |
| if (!strcmp(_clname, "TestObject")) |
| return static_cast<void*>(const_cast< TestObject*>(this)); |
| return QObject::qt_metacast(_clname); |
| } |
| |
| int TestObject::qt_metacall(QMetaObject::Call _c, int _id, void **_a) |
| { |
| _id = QObject::qt_metacall(_c, _id, _a); |
| if (_id < 0) |
| return _id; |
| int ownMethodCount = m_metaObject->methodCount() - m_metaObject->methodOffset(); |
| int ownPropertyCount = m_metaObject->propertyCount() - m_metaObject->propertyOffset(); |
| if (_c == QMetaObject::InvokeMetaMethod) { |
| if (_id < ownMethodCount) |
| qt_static_metacall(this, _c, _id, _a); |
| _id -= ownMethodCount; |
| } |
| #ifndef QT_NO_PROPERTIES |
| else if (_c == QMetaObject::ReadProperty) { |
| void *_v = _a[0]; |
| switch (_id) { |
| case 0: *reinterpret_cast< int*>(_v) = intProp(); break; |
| default: if (_id < ownPropertyCount) { |
| QMetaProperty prop = m_metaObject->property(m_metaObject->propertyOffset() + _id); |
| qFatal("You forgot to add a case for ReadProperty %s", prop.name()); |
| } |
| } |
| _id -= ownPropertyCount; |
| } else if (_c == QMetaObject::WriteProperty) { |
| void *_v = _a[0]; |
| switch (_id) { |
| case 0: setIntProp(*reinterpret_cast< int*>(_v)); break; |
| default: if (_id < ownPropertyCount) { |
| QMetaProperty prop = m_metaObject->property(m_metaObject->propertyOffset() + _id); |
| qFatal("You forgot to add a case for WriteProperty %s", prop.name()); |
| } |
| } |
| _id -= ownPropertyCount; |
| } else if (_c == QMetaObject::ResetProperty) { |
| _id -= ownPropertyCount; |
| } else if (_c == QMetaObject::QueryPropertyDesignable) { |
| _id -= ownPropertyCount; |
| } else if (_c == QMetaObject::QueryPropertyScriptable) { |
| _id -= ownPropertyCount; |
| } else if (_c == QMetaObject::QueryPropertyStored) { |
| _id -= ownPropertyCount; |
| } else if (_c == QMetaObject::QueryPropertyEditable) { |
| _id -= ownPropertyCount; |
| } else if (_c == QMetaObject::QueryPropertyUser) { |
| _id -= ownPropertyCount; |
| } |
| #endif // QT_NO_PROPERTIES |
| return _id; |
| } |
| |
| // SIGNAL 0 |
| void TestObject::intPropChanged(int _t1) |
| { |
| void *_a[] = { 0, const_cast<void*>(reinterpret_cast<const void*>(&_t1)) }; |
| QMetaObject::activate(this, m_metaObject, 0, _a); |
| } |
| |
| |
| void tst_QMetaObjectBuilder::usage_signal() |
| { |
| QScopedPointer<TestObject> testObject(new TestObject); |
| |
| QSignalSpy propChangedSpy(testObject.data(), &TestObject::intPropChanged); |
| testObject->emitIntPropChanged(); |
| QCOMPARE(propChangedSpy.count(), 1); |
| QCOMPARE(propChangedSpy.at(0).count(), 1); |
| QCOMPARE(propChangedSpy.at(0).at(0).toInt(), testObject->intProp()); |
| } |
| |
| void tst_QMetaObjectBuilder::usage_property() |
| { |
| QScopedPointer<TestObject> testObject(new TestObject); |
| |
| QVariant prop = testObject->property("intProp"); |
| QCOMPARE(prop.type(), QVariant::Int); |
| QCOMPARE(prop.toInt(), testObject->intProp()); |
| |
| QSignalSpy propChangedSpy(testObject.data(), &TestObject::intPropChanged); |
| QVERIFY(testObject->intProp() != 123); |
| testObject->setProperty("intProp", 123); |
| QCOMPARE(propChangedSpy.count(), 1); |
| prop = testObject->property("intProp"); |
| QCOMPARE(prop.type(), QVariant::Int); |
| QCOMPARE(prop.toInt(), 123); |
| } |
| |
| void tst_QMetaObjectBuilder::usage_slot() |
| { |
| QScopedPointer<TestObject> testObject(new TestObject); |
| |
| int index = testObject->metaObject()->indexOfMethod("voidSlotInt(int)"); |
| QVERIFY(index != -1); |
| QMetaMethod voidSlotInt = testObject->metaObject()->method(index); |
| |
| QCOMPARE(testObject->voidSlotIntArgument(), -1); |
| QVERIFY(voidSlotInt.invoke(testObject.data(), Q_ARG(int, 123))); |
| QCOMPARE(testObject->voidSlotIntArgument(), 123); |
| } |
| |
| void tst_QMetaObjectBuilder::usage_method() |
| { |
| QScopedPointer<TestObject> testObject(new TestObject); |
| |
| int index = testObject->metaObject()->indexOfMethod("listInvokableQRealQString(qreal,QString)"); |
| QVERIFY(index != -1); |
| QMetaMethod listInvokableQRealQString = testObject->metaObject()->method(index); |
| QVariantList list; |
| QVERIFY(listInvokableQRealQString.invoke(testObject.data(), Q_RETURN_ARG(QVariantList, list), |
| Q_ARG(qreal, 123.0), Q_ARG(QString, "ciao"))); |
| QCOMPARE(list.size(), 2); |
| QCOMPARE(list.at(0).type(), QVariant::Type(QMetaType::QReal)); |
| QCOMPARE(list.at(0).toDouble(), double(123)); |
| QCOMPARE(list.at(1).type(), QVariant::String); |
| QCOMPARE(list.at(1).toString(), QString::fromLatin1("ciao")); |
| } |
| |
| void tst_QMetaObjectBuilder::usage_constructor() |
| { |
| QScopedPointer<TestObject> testObject(new TestObject); |
| |
| QCOMPARE(testObject->metaObject()->constructorCount(), 2); |
| QScopedPointer<QObject> testInstance(testObject->metaObject()->newInstance()); |
| QVERIFY(testInstance != 0); |
| QScopedPointer<QObject> testInstance2(testObject->metaObject()->newInstance(Q_ARG(QObject*, testInstance.data()))); |
| QVERIFY(testInstance2 != 0); |
| QCOMPARE(testInstance2->parent(), testInstance.data()); |
| } |
| |
| void tst_QMetaObjectBuilder::usage_connect() |
| { |
| QScopedPointer<TestObject> testObject(new TestObject); |
| |
| QVERIFY(QObject::connect(testObject.data(), SIGNAL(intPropChanged(int)), |
| testObject.data(), SLOT(voidSlotInt(int)))); |
| |
| QCOMPARE(testObject->voidSlotIntArgument(), -1); |
| testObject->setProperty("intProp", 123); |
| QCOMPARE(testObject->voidSlotIntArgument(), 123); |
| |
| QVERIFY(QObject::disconnect(testObject.data(), SIGNAL(intPropChanged(int)), |
| testObject.data(), SLOT(voidSlotInt(int)))); |
| } |
| |
| void tst_QMetaObjectBuilder::usage_templateConnect() |
| { |
| QScopedPointer<TestObject> testObject(new TestObject); |
| |
| QMetaObject::Connection con = QObject::connect(testObject.data(), &TestObject::intPropChanged, |
| testObject.data(), &TestObject::voidSlotInt); |
| QVERIFY(con); |
| |
| QCOMPARE(testObject->voidSlotIntArgument(), -1); |
| testObject->setProperty("intProp", 123); |
| QCOMPARE(testObject->voidSlotIntArgument(), 123); |
| |
| QVERIFY(QObject::disconnect(testObject.data(), &TestObject::intPropChanged, |
| testObject.data(), &TestObject::voidSlotInt)); |
| |
| // Something that isn't a signal |
| QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in TestObject"); |
| con = QObject::connect(testObject.data(), &TestObject::setIntProp, |
| testObject.data(), &TestObject::intPropChanged); |
| QVERIFY(!con); |
| } |
| |
| void tst_QMetaObjectBuilder::classNameFirstInStringData() |
| { |
| QMetaObjectBuilder builder; |
| builder.addMetaObject(&SomethingOfEverything::staticMetaObject); |
| builder.setClassName(QByteArrayLiteral("TestClass")); |
| QMetaObject *mo = builder.toMetaObject(); |
| |
| QByteArrayDataPtr header; |
| header.ptr = const_cast<QByteArrayData*>(mo->d.stringdata); |
| QCOMPARE(QByteArray(header), QByteArrayLiteral("TestClass")); |
| |
| free(mo); |
| } |
| |
| QTEST_MAIN(tst_QMetaObjectBuilder) |
| |
| #include "tst_qmetaobjectbuilder.moc" |