qt5base-lts/tests/auto/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
Lorn Potter 0cb7a66989 add qmetaobjectbuilder to qtbase.
Use the QMetaObjectBuilder code from declarative and add it to libQtCore.

    Consolidating various QMetaObjectBuilder implimentations to avoid
    code duplications in those modules.

    This is currently still a private API only.

Change-Id: Ie363b4fd769c41efbb3caa7fb1d6f77af13c3c9c
Reviewed-on: http://codereview.qt-project.org/6287
Sanity-Review: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Alex <alex.blasche@nokia.com>
2011-10-11 07:02:14 +02:00

1269 lines
45 KiB
C++

/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <QtCore/qlocale.h>
#include <private/qmetaobjectbuilder_p.h>
class tst_QMetaObjectBuilder : public QObject
{
Q_OBJECT
public:
tst_QMetaObjectBuilder() {}
~tst_QMetaObjectBuilder() {}
private slots:
void mocVersionCheck();
void create();
void className();
void superClass();
void flags();
void method();
void slot();
void signal();
void constructor();
void property();
void notifySignal();
void enumerator();
void classInfo();
void relatedMetaObject();
void staticMetacall();
void copyMetaObject();
void serialize();
void removeNotifySignal();
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(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&) {}
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::mocVersionCheck()
{
// This test will fail when the moc version number is changed.
// It is intended as a reminder to also update QMetaObjectBuilder
// whenenver moc changes. Once QMetaObjectBuilder has been
// updated, this test can be changed to check for the next version.
int version = int(QObject::staticMetaObject.d.data[0]);
QVERIFY(version == 4 || version == 5 || version == 6);
version = int(staticMetaObject.d.data[0]);
QVERIFY(version == 4 || version == 5 || version == 6);
}
void tst_QMetaObjectBuilder::create()
{
QMetaObjectBuilder builder;
QVERIFY(builder.className().isEmpty());
QVERIFY(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() == 0);
}
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);
QVERIFY(builder.superClass() == &QObject::staticMetaObject);
// Change it again.
builder.setSuperClass(&staticMetaObject);
QVERIFY(builder.superClass() == &staticMetaObject);
// Clone the super class off a static QMetaObject.
builder.addMetaObject(&QObject::staticMetaObject, QMetaObjectBuilder::SuperClass);
QVERIFY(builder.superClass() == 0);
builder.addMetaObject(&staticMetaObject, QMetaObjectBuilder::SuperClass);
QVERIFY(builder.superClass() == staticMetaObject.superClass());
// Check that nothing else changed.
QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::SuperClass));
}
void tst_QMetaObjectBuilder::flags()
{
QMetaObjectBuilder builder;
// Check default
QVERIFY(builder.flags() == 0);
// Set flags
builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
QVERIFY(builder.flags() == QMetaObjectBuilder::DynamicMetaObject);
}
void tst_QMetaObjectBuilder::method()
{
QMetaObjectBuilder builder;
// Check null method
QMetaMethodBuilder nullMethod;
QCOMPARE(nullMethod.signature(), QByteArray());
QVERIFY(nullMethod.methodType() == QMetaMethod::Method);
QVERIFY(nullMethod.returnType().isEmpty());
QVERIFY(nullMethod.parameterNames().isEmpty());
QVERIFY(nullMethod.tag().isEmpty());
QVERIFY(nullMethod.access() == QMetaMethod::Public);
QCOMPARE(nullMethod.attributes(), 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)"));
QVERIFY(method1.methodType() == QMetaMethod::Method);
QVERIFY(method1.returnType().isEmpty());
QVERIFY(method1.parameterNames().isEmpty());
QVERIFY(method1.tag().isEmpty());
QVERIFY(method1.access() == QMetaMethod::Public);
QCOMPARE(method1.attributes(), 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)"));
QVERIFY(method2.methodType() == QMetaMethod::Method);
QCOMPARE(method2.returnType(), QByteArray("int"));
QVERIFY(method2.parameterNames().isEmpty());
QVERIFY(method2.tag().isEmpty());
QVERIFY(method2.access() == QMetaMethod::Public);
QCOMPARE(method2.attributes(), 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);
// Check that method1 is changed, but method2 is not.
QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
QVERIFY(method1.methodType() == QMetaMethod::Method);
QCOMPARE(method1.returnType(), QByteArray("int"));
QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b");
QCOMPARE(method1.tag(), QByteArray("tag"));
QVERIFY(method1.access() == QMetaMethod::Private);
QCOMPARE(method1.attributes(), 42);
QCOMPARE(method1.index(), 0);
QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
QVERIFY(method2.methodType() == QMetaMethod::Method);
QCOMPARE(method2.returnType(), QByteArray("int"));
QVERIFY(method2.parameterNames().isEmpty());
QVERIFY(method2.tag().isEmpty());
QVERIFY(method2.access() == QMetaMethod::Public);
QCOMPARE(method2.attributes(), 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);
// This time check that only method2 changed.
QCOMPARE(method1.signature(), QByteArray("foo(QString,int)"));
QVERIFY(method1.methodType() == QMetaMethod::Method);
QCOMPARE(method1.returnType(), QByteArray("int"));
QCOMPARE(method1.parameterNames(), QList<QByteArray>() << "a" << "b");
QCOMPARE(method1.tag(), QByteArray("tag"));
QVERIFY(method1.access() == QMetaMethod::Private);
QCOMPARE(method1.attributes(), 42);
QCOMPARE(method1.index(), 0);
QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
QVERIFY(method2.methodType() == QMetaMethod::Method);
QCOMPARE(method2.returnType(), QByteArray("QString"));
QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c");
QCOMPARE(method2.tag(), QByteArray("Q_FOO"));
QVERIFY(method2.access() == QMetaMethod::Protected);
QCOMPARE(method2.attributes(), 24);
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)"));
QVERIFY(method2.methodType() == QMetaMethod::Method);
QCOMPARE(method2.returnType(), QByteArray("QString"));
QCOMPARE(method2.parameterNames(), QList<QByteArray>() << "c");
QCOMPARE(method2.tag(), QByteArray("Q_FOO"));
QVERIFY(method2.access() == QMetaMethod::Protected);
QCOMPARE(method2.attributes(), 24);
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)"));
QVERIFY(method1.methodType() == QMetaMethod::Slot);
QVERIFY(method1.returnType().isEmpty());
QVERIFY(method1.parameterNames().isEmpty());
QVERIFY(method1.tag().isEmpty());
QVERIFY(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)"));
QVERIFY(method2.methodType() == QMetaMethod::Slot);
QVERIFY(method2.returnType().isEmpty());
QVERIFY(method2.parameterNames().isEmpty());
QVERIFY(method2.tag().isEmpty());
QVERIFY(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)"));
QVERIFY(method1.methodType() == QMetaMethod::Signal);
QVERIFY(method1.returnType().isEmpty());
QVERIFY(method1.parameterNames().isEmpty());
QVERIFY(method1.tag().isEmpty());
QVERIFY(method1.access() == QMetaMethod::Protected);
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)"));
QVERIFY(method2.methodType() == QMetaMethod::Signal);
QVERIFY(method2.returnType().isEmpty());
QVERIFY(method2.parameterNames().isEmpty());
QVERIFY(method2.tag().isEmpty());
QVERIFY(method2.access() == QMetaMethod::Protected);
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)"));
QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
QVERIFY(ctor1.returnType().isEmpty());
QVERIFY(ctor1.parameterNames().isEmpty());
QVERIFY(ctor1.tag().isEmpty());
QVERIFY(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)"));
QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
QVERIFY(ctor2.returnType().isEmpty());
QVERIFY(ctor2.parameterNames().isEmpty());
QVERIFY(ctor2.tag().isEmpty());
QVERIFY(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)"));
QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
QCOMPARE(ctor1.returnType(), QByteArray("int"));
QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b");
QCOMPARE(ctor1.tag(), QByteArray("tag"));
QVERIFY(ctor1.access() == QMetaMethod::Private);
QCOMPARE(ctor1.attributes(), 42);
QCOMPARE(ctor1.index(), 0);
QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
QVERIFY(ctor2.returnType().isEmpty());
QVERIFY(ctor2.parameterNames().isEmpty());
QVERIFY(ctor2.tag().isEmpty());
QVERIFY(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)"));
QVERIFY(ctor1.methodType() == QMetaMethod::Constructor);
QCOMPARE(ctor1.returnType(), QByteArray("int"));
QCOMPARE(ctor1.parameterNames(), QList<QByteArray>() << "a" << "b");
QCOMPARE(ctor1.tag(), QByteArray("tag"));
QVERIFY(ctor1.access() == QMetaMethod::Private);
QCOMPARE(ctor1.attributes(), 42);
QCOMPARE(ctor1.index(), 0);
QCOMPARE(ctor2.signature(), QByteArray("bar(QString)"));
QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
QCOMPARE(ctor2.returnType(), QByteArray("QString"));
QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c");
QCOMPARE(ctor2.tag(), QByteArray("Q_FOO"));
QVERIFY(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)"));
QVERIFY(ctor2.methodType() == QMetaMethod::Constructor);
QCOMPARE(ctor2.returnType(), QByteArray("QString"));
QCOMPARE(ctor2.parameterNames(), QList<QByteArray>() << "c");
QCOMPARE(ctor2.tag(), QByteArray("Q_FOO"));
QVERIFY(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()"));
QVERIFY(prototypeConstructor.methodType() == QMetaMethod::Constructor);
QCOMPARE(prototypeConstructor.returnType(), QByteArray());
QVERIFY(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);
// 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.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.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);
// 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());
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());
// 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.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::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());
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());
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);
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());
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());
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());
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());
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());
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());
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());
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);
QVERIFY(builder.relatedMetaObject(0) == &QObject::staticMetaObject);
QVERIFY(builder.relatedMetaObject(1) == &staticMetaObject);
QCOMPARE(builder.relatedMetaObjectCount(), 2);
// Remove the first one and check again.
builder.removeRelatedMetaObject(0);
QVERIFY(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));
qFree(meta);
QMetaObjectBuilder builder2(&staticMetaObject);
meta = builder2.toMetaObject();
QVERIFY(sameMetaObject(meta, &staticMetaObject));
qFree(meta);
QMetaObjectBuilder builder3(&SomethingOfEverything::staticMetaObject);
meta = builder3.toMetaObject();
QVERIFY(sameMetaObject(meta, &SomethingOfEverything::staticMetaObject));
qFree(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));
qFree(meta);
qFree(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());
}
}
// Check that removing a method updates notify signals appropriately
void tst_QMetaObjectBuilder::removeNotifySignal()
{
QMetaObjectBuilder builder;
QMetaMethodBuilder method1 = builder.addSignal("foo(const QString&, int)");
QMetaMethodBuilder method2 = builder.addSignal("bar(QString)");
// Setup property
QMetaPropertyBuilder prop = builder.addProperty("prop", "const QString &");
prop.setNotifySignal(method2);
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 (QByteArray(method1.signature()) != QByteArray(method2.signature()))
return false;
if (QByteArray(method1.typeName()) != QByteArray(method2.typeName()))
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;
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;
}
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 QMetaObject **objects1 = 0;
const QMetaObject **objects2 = 0;
if (meta1->d.data[0] == meta2->d.data[0] && meta1->d.data[0] >= 2) {
QMetaObjectExtraData *extra1 = (QMetaObjectExtraData *)(meta1->d.extradata);
QMetaObjectExtraData *extra2 = (QMetaObjectExtraData *)(meta2->d.extradata);
if (extra1 && !extra2)
return false;
if (extra2 && !extra1)
return false;
if (extra1 && extra2) {
if (extra1->static_metacall != extra2->static_metacall)
return false;
objects1 = extra1->objects;
objects2 = extra1->objects;
}
} else if (meta1->d.data[0] == meta2->d.data[0] && meta1->d.data[0] == 1) {
objects1 = (const QMetaObject **)(meta1->d.extradata);
objects2 = (const QMetaObject **)(meta2->d.extradata);
}
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;
}
QTEST_MAIN(tst_QMetaObjectBuilder)
#include "tst_qmetaobjectbuilder.moc"