summaryrefslogtreecommitdiffstats
path: root/tests/auto/declarative/qmetaobjectbuilder
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2009-11-03 04:02:37 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2009-11-03 04:02:37 (GMT)
commit43c15688888b433d6d3c01c0d68168fec81cf06a (patch)
treed21df2007e263276213d021a77f80474d7607304 /tests/auto/declarative/qmetaobjectbuilder
parent6a8718838ab002237540fb8490063a410ee4f95d (diff)
downloadQt-43c15688888b433d6d3c01c0d68168fec81cf06a.zip
Qt-43c15688888b433d6d3c01c0d68168fec81cf06a.tar.gz
Qt-43c15688888b433d6d3c01c0d68168fec81cf06a.tar.bz2
Add QMetaObjectBuilder test
Diffstat (limited to 'tests/auto/declarative/qmetaobjectbuilder')
-rw-r--r--tests/auto/declarative/qmetaobjectbuilder/qmetaobjectbuilder.pro7
-rw-r--r--tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp1059
2 files changed, 1066 insertions, 0 deletions
diff --git a/tests/auto/declarative/qmetaobjectbuilder/qmetaobjectbuilder.pro b/tests/auto/declarative/qmetaobjectbuilder/qmetaobjectbuilder.pro
new file mode 100644
index 0000000..94ffe4b
--- /dev/null
+++ b/tests/auto/declarative/qmetaobjectbuilder/qmetaobjectbuilder.pro
@@ -0,0 +1,7 @@
+load(qttest_p4)
+contains(QT_CONFIG,declarative): QT += declarative
+macx:CONFIG -= app_bundle
+
+SOURCES += \
+ tst_qmetaobjectbuilder.cpp
+
diff --git a/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
new file mode 100644
index 0000000..0dac963
--- /dev/null
+++ b/tests/auto/declarative/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
@@ -0,0 +1,1059 @@
+/****************************************************************************
+**
+** Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $TROLLTECH_DUAL_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 method();
+ void slot();
+ void signal();
+ void constructor();
+ void property();
+ void notifySignal();
+ void enumerator();
+ void classInfo();
+ void relatedMetaObject();
+ void staticMetacall();
+ void copyMetaObject();
+ void serialize();
+
+private:
+ static bool checkForSideEffects
+ (const QMetaObjectBuilder& builder,
+ QMetaObjectBuilder::AddMembers members);
+ static bool sameMetaObject
+ (const QMetaObject *meta1, const QMetaObject *meta2);
+};
+
+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.
+ QCOMPARE(int(QObject::staticMetaObject.d.data[0]), 2);
+ QCOMPARE(int(staticMetaObject.d.data[0]), 2);
+}
+
+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::method()
+{
+ QMetaObjectBuilder builder;
+
+ // 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)");
+ QCOMPARE(method2.signature(), QByteArray("bar(QString)"));
+ QVERIFY(method2.methodType() == QMetaMethod::Method);
+ 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.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);
+ 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);
+
+ // 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);
+
+ // 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);
+
+ // 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);
+
+ // 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);
+
+ // 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);
+
+ // Check that nothing else changed.
+ QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Constructors));
+}
+
+void tst_QMetaObjectBuilder::property()
+{
+ QMetaObjectBuilder builder;
+
+ // 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());
+ 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());
+ 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);
+
+ // Modify the attributes on prop1.
+ prop1.setReadable(false);
+ prop1.setWritable(false);
+ prop1.setResettable(true);
+ prop1.setDesignable(true);
+ prop1.setScriptable(true);
+ prop1.setStored(true);
+ prop1.setEditable(true);
+ prop1.setUser(true);
+ prop1.setStdCppSet(true);
+ prop1.setEnumOrFlag(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(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());
+
+ // 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());
+ 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); \
+ } 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))
+#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 that nothing else changed.
+ QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Properties));
+}
+
+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);
+
+ // 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.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.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.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.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.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 int smetacall(QMetaObject::Call, int, void **)
+{
+ return 0;
+}
+
+void tst_QMetaObjectBuilder::staticMetacall()
+{
+ QMetaObjectBuilder builder;
+ QVERIFY(!builder.staticMetacallFunction());
+ builder.setStaticMetacallFunction(smetacall);
+ QVERIFY(builder.staticMetacallFunction() == smetacall);
+ QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::StaticMetacall));
+}
+
+// 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&);
+};
+
+// 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()
+{
+ 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);
+}
+
+// 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"