summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex <qt-info@nokia.com>2010-01-28 17:47:47 +1000
committerAlex <qt-info@nokia.com>2010-01-28 17:47:47 +1000
commitaa016515052e8e793fa227d24fa3f73ac61ae7e9 (patch)
tree06b3e6c1bb05ed577fe53e44a4742f140632ff9f
parent4c8246f393f60e04432b460f528671be7786cbb8 (diff)
meta method invocation w/o return type
-rw-r--r--examples/sfwipcclient/main.cpp40
-rw-r--r--examples/sfwipcservice/main.cpp33
-rw-r--r--src/serviceframework/ipc/objectendpoint.cpp101
-rw-r--r--src/serviceframework/ipc/objectendpoint_p.h2
-rw-r--r--src/serviceframework/ipc/proxyobject.cpp76
-rw-r--r--src/serviceframework/ipc/proxyobject_p.h3
-rw-r--r--src/serviceframework/ipc/qmetaobjectbuilder_p.h8
-rw-r--r--src/serviceframework/ipc/qservicepackage.cpp16
-rw-r--r--src/serviceframework/ipc/qservicepackage_p.h12
-rw-r--r--src/serviceframework/qservicemanager.cpp5
-rw-r--r--tests/auto/auto.pro3
-rw-r--r--tests/auto/qmetaobjectbuilder/qmetaobjectbuilder.pro37
-rw-r--r--tests/auto/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp1286
13 files changed, 1563 insertions, 59 deletions
diff --git a/examples/sfwipcclient/main.cpp b/examples/sfwipcclient/main.cpp
index 3dfc6d417d..23dd285b23 100644
--- a/examples/sfwipcclient/main.cpp
+++ b/examples/sfwipcclient/main.cpp
@@ -1,6 +1,8 @@
#include <QApplication>
#include "qservicemanager.h"
#include <QTimer>
+#include <QMetaObject>
+#include <QMetaMethod>
QTM_USE_NAMESPACE
@@ -16,11 +18,47 @@ public:
qWarning() << "Cannot find service. Error:" << manager.error();
QTimer::singleShot(1000, this, SLOT(killProcess()));
}
+ checkServiceObject();
+ }
+
+public slots:
+ void checkServiceObject()
+ {
+ const QMetaObject* mo = service->metaObject();
+ qDebug() << "ServiceObject class: " << mo->className() << mo->superClass() << mo->superClass()->className();
+ qDebug() << "Methods:" << mo->methodCount()- mo->methodOffset() << "(" << mo->methodCount() << ")";
+ for (int i=0; i< mo->methodCount(); i++) {
+ QMetaMethod method = mo->method(i);
+ QString type;
+ switch(method.methodType()) {
+ case QMetaMethod::Signal:
+ type = "signal"; break;
+ case QMetaMethod::Slot:
+ type = "slot"; break;
+ case QMetaMethod::Constructor:
+ type = "constrcutor"; break;
+ case QMetaMethod::Method:
+ type = "method"; break;
+ }
+ qDebug() << " " << i << "." << method.signature() << type;
+
+ }
+
+ QTimer::singleShot(1000, this, SLOT(useService()));
+ }
+
+ void useService()
+ {
+ qDebug() << "Invoking testSlot()";
+ QMetaObject::invokeMethod( service, "testSlot" );
+
+ qDebug() << "Invoking testSlotWithArgs(QByteArray, int, QVariant)";
+ QMetaObject::invokeMethod( service, "testSlotWithArgs",
+ Q_ARG(QByteArray, "array"), Q_ARG(int, 5), Q_ARG(QVariant, "dddd"));
QTimer::singleShot(1000, this, SLOT(killService()));
}
-public slots:
void killService()
{
delete service;
diff --git a/examples/sfwipcservice/main.cpp b/examples/sfwipcservice/main.cpp
index 4129b89fb6..d7c65cf507 100644
--- a/examples/sfwipcservice/main.cpp
+++ b/examples/sfwipcservice/main.cpp
@@ -13,11 +13,26 @@ class TestService : public QObject
Q_SERVICE(TestService, "com.nokia.qt.interface", "3.4")
public:
- Q_INVOKABLE TestService(QObject* parent = 0)
+ TestService(QObject* parent = 0)
: QObject(parent)
{
}
+Q_SIGNALS:
+ void testSignal();
+public slots:
+ void testSlot()
+ {
+ qDebug() << "TestService::testSlot() called";
+ }
+
+ void testSlotWithArgs(const QByteArray& d, int a, const QVariant& variant)
+ {
+ QString output("%1, %2, %3");
+ output = output.arg(d.constData()).arg(a).arg(variant.toString());
+ qDebug() << "TestService::testSlotWithArgs(" << output << ") called";
+ }
+
};
class TestService2 : public QObject
{
@@ -25,10 +40,24 @@ class TestService2 : public QObject
Q_SERVICE(TestService2, "com.nokia.qt.interface", "3.5")
public:
- TestService2(QObject* parent = 0)
+ /*Q_INVOKABLE*/ TestService2(QObject* parent = 0)
: QObject(parent)
{
}
+Q_SIGNALS:
+ void testSignal();
+
+public slots:
+ void testSlot() {
+ qDebug() << "TestService2::testSlot() called";
+ }
+
+ void testSlotWithArgs(const QByteArray& d, int a, const QVariant& variant)
+ {
+ QString output("%1, %2, %3");
+ output = output.arg(d.constData()).arg(a).arg(variant.toString());
+ qDebug() << "TestService2::testSlotWithArgs(" << output << ") called";
+ }
};
void unregisterExampleService()
diff --git a/src/serviceframework/ipc/objectendpoint.cpp b/src/serviceframework/ipc/objectendpoint.cpp
index e3fcaf1238..925b9adb5a 100644
--- a/src/serviceframework/ipc/objectendpoint.cpp
+++ b/src/serviceframework/ipc/objectendpoint.cpp
@@ -103,16 +103,15 @@ QObject* ObjectEndPoint::constructProxy(const QServiceTypeIdent& ident)
//return meta object
QServicePackage p;
p.d = new QServicePackagePrivate();
- p.d->type = QServicePackage::ObjectCreation;
- p.d->id = QUuid::createUuid();
+ p.d->messageId = QUuid::createUuid();
p.d->typeId = ident;
Response* response = new Response();
- openRequests()->insert(p.d->id, response);
+ openRequests()->insert(p.d->messageId, response);
dispatch->writePackage(p);
- waitForResponse(p.d->id);
+ waitForResponse(p.d->messageId);
if (response->isFinished) {
if (response->result == 0)
@@ -123,7 +122,7 @@ QObject* ObjectEndPoint::constructProxy(const QServiceTypeIdent& ident)
qDebug() << "response passed but not finished";
}
- openRequests()->take(p.d->id);
+ openRequests()->take(p.d->messageId);
delete response;
return service;
@@ -137,7 +136,7 @@ void ObjectEndPoint::newPackageReady()
if (!p.isValid())
continue;
- switch(p.d->type) {
+ switch(p.d->packageType) {
case QServicePackage::ObjectCreation:
objectRequest(p);
break;
@@ -155,21 +154,17 @@ void ObjectEndPoint::objectRequest(const QServicePackage& p)
{
if (p.d->responseType != QServicePackage::NotAResponse ) {
qDebug() << p;
- Response* response = openRequests()->value(p.d->id);
+ Response* response = openRequests()->value(p.d->messageId);
if (p.d->responseType == QServicePackage::Failed) {
response->result = 0;
response->isFinished = true;
+ QTimer::singleShot(0, this, SIGNAL(pendingRequestFinished()));
qWarning() << "Service instanciation failed";
return;
}
- //deserialize meta object
- QByteArray payload = p.d->payload.toByteArray();
- QMetaObject mo;
- QMetaObjectBuilder::fromRelocatableData(&mo, 0, payload);
- qDebug() << mo.className() << payload.size() << sizeof(mo);
-
+ //deserialize meta object and
//create proxy object
- QServiceProxy* proxy = new QServiceProxy(payload);
+ QServiceProxy* proxy = new QServiceProxy(p.d->payload.toByteArray(), this);
response->result = reinterpret_cast<void *>(proxy);
response->isFinished = true;
@@ -190,16 +185,11 @@ void ObjectEndPoint::objectRequest(const QServicePackage& p)
}
//serialize meta object
- bool ok = false;
+ QByteArray data;
+ QDataStream stream( &data, QIODevice::WriteOnly | QIODevice::Append );
QMetaObjectBuilder builder(meta);
+ builder.serialize(stream);
- const QByteArray serializedMetaObject = builder.toRelocatableData(&ok);
- if (!ok) {
- qWarning() << "Cannot serialize QMetaObject";
- dispatch->writePackage(response);
- return;
- }
-
//instanciate service object from type register
service = m->createObjectInstance(p.d->typeId, serviceInstanceId);
if (!service) {
@@ -212,23 +202,82 @@ void ObjectEndPoint::objectRequest(const QServicePackage& p)
typeIdent = p.d->typeId;
response.d->typeId = p.d->typeId;
response.d->responseType = QServicePackage::Success;
- response.d->payload = QVariant(serializedMetaObject);
+ response.d->payload = QVariant(data);
dispatch->writePackage(response);
}
}
-
+
+#define QVARIANT_ARG(arg) (arg.isValid?
void ObjectEndPoint::methodCall(const QServicePackage& p)
{
- if (p.d->responseType != QServicePackage::NotAResponse ) {
+ if (p.d->responseType == QServicePackage::NotAResponse ) {
qDebug() << p;
- //TODO
+ QByteArray data = p.d->payload.toByteArray();
+ QDataStream stream(&data, QIODevice::ReadOnly);
+ int metaIndex = -1;
+ QVariantList args;
+ stream >> metaIndex;
+ stream >> args;
+
+ QMetaMethod method = service->metaObject()->method(metaIndex);
+ const int returnType = QMetaType::type(method.typeName());
+
+ const char* typenames[] = {0,0,0,0,0,0,0,0,0,0};
+ const void* param[] = {0,0,0,0,0,0,0,0,0,0};
+
+ for(int i=0; i<args.size(); i++) {
+ typenames[i] = args[i].typeName();
+ param[i] = args[i].constData();
+ }
+
+ if (returnType == QMetaType::Void) {
+
+ bool result = method.invoke(service,
+ QGenericArgument(typenames[0], param[0]),
+ QGenericArgument(typenames[1], param[1]),
+ QGenericArgument(typenames[2], param[2]),
+ QGenericArgument(typenames[3], param[3]),
+ QGenericArgument(typenames[4], param[4]),
+ QGenericArgument(typenames[5], param[5]),
+ QGenericArgument(typenames[6], param[6]),
+ QGenericArgument(typenames[7], param[7]),
+ QGenericArgument(typenames[8], param[8]),
+ QGenericArgument(typenames[9], param[9]));
+ if (!result)
+ qWarning( "%s::%s cannot be called.", service->metaObject()->className(), method.signature());
+ } else {
+ //TODO
+ }
} else {
qDebug() << p;
//TODO
}
}
+/*!
+ Will block if return value expected
+*/
+QVariant ObjectEndPoint::invokeRemote(int metaIndex, QVariantList args, int returnType)
+{
+ QServicePackage p;
+ p.d = new QServicePackagePrivate();
+ p.d->packageType = QServicePackage::MethodCall;
+ p.d->messageId = QUuid::createUuid();
+
+ if (returnType == QMetaType::Void) {
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly|QIODevice::Append);
+ stream << metaIndex << args;
+ p.d->payload = data;
+ dispatch->writePackage(p);
+ } else {
+ //create response and block for answer
+ }
+
+ return QVariant();
+}
+
void ObjectEndPoint::waitForResponse(const QUuid& requestId)
{
if (openRequests()->contains(requestId) ) {
diff --git a/src/serviceframework/ipc/objectendpoint_p.h b/src/serviceframework/ipc/objectendpoint_p.h
index 30e999dde0..703a61436e 100644
--- a/src/serviceframework/ipc/objectendpoint_p.h
+++ b/src/serviceframework/ipc/objectendpoint_p.h
@@ -66,6 +66,8 @@ public:
void objectRequest(const QServicePackage& p);
void methodCall(const QServicePackage& p);
+ QVariant invokeRemote(int metaIndex, QVariantList args, int returnType);
+
Q_SIGNALS:
void pendingRequestFinished();
diff --git a/src/serviceframework/ipc/proxyobject.cpp b/src/serviceframework/ipc/proxyobject.cpp
index a62d5b5713..156e8668ce 100644
--- a/src/serviceframework/ipc/proxyobject.cpp
+++ b/src/serviceframework/ipc/proxyobject.cpp
@@ -51,21 +51,35 @@ class QServiceProxyPrivate
public:
QByteArray metadata;
QMetaObject* meta;
+ ObjectEndPoint* endPoint;
};
-QServiceProxy::QServiceProxy(const QByteArray& metadata, QObject* parent)
+QServiceProxy::QServiceProxy(const QByteArray& metadata, ObjectEndPoint* endPoint, QObject* parent)
: QObject(parent)
{
+ Q_ASSERT(endPoint);
d = new QServiceProxyPrivate();
d->metadata = metadata;
- d->meta = new QMetaObject();
+ d->meta = 0;
+ d->endPoint = endPoint;
- QMetaObjectBuilder::fromRelocatableData(d->meta, 0, d->metadata);
+ QDataStream stream(d->metadata);
+ QMetaObjectBuilder builder;
+ QMap<QByteArray, const QMetaObject*> refs;
+
+ builder.deserialize(stream, refs);
+ if (stream.status() != QDataStream::Ok) {
+ qWarning() << "Invalid metaObject for service received";
+ } else {
+ d->meta = builder.toMetaObject();
+ qWarning() << "Proxy object for" << d->meta->className() << "created.";
+ }
}
QServiceProxy::~QServiceProxy()
{
- delete d->meta;
+ if (d->meta)
+ delete d->meta;
delete d;
}
@@ -78,16 +92,64 @@ const QMetaObject* QServiceProxy::metaObject() const
int QServiceProxy::qt_metacall(QMetaObject::Call c, int id, void **a)
{
id = QObject::qt_metacall(c, id, a);
- if (id < 0)
+ if (id < 0 || !d->meta)
return id;
- //TODO catch everything bound for remote service object
+ if (c == QMetaObject::InvokeMetaMethod) {
+ const int mcount = d->meta->methodCount() - d->meta->methodOffset();
+ const int metaIndex = id + d->meta->methodOffset();
+
+ QMetaMethod method = d->meta->method(metaIndex);
+ const int returnType = QMetaType::type(method.typeName());
+
+ //process arguments
+ const QList<QByteArray> pTypes = method.parameterTypes();
+ const int pTypesCount = pTypes.count();
+ QVariantList args ;
+ if (pTypesCount > 10) {
+ qWarning() << "Cannot call" << method.signature() << ". More than 10 parameter.";
+ return id;
+ }
+ for (int i=0; i < pTypesCount; i++) {
+ const QByteArray& t = pTypes[i];
+
+ int variantType = QVariant::nameToType(t);
+ if (variantType == QVariant::UserType)
+ variantType = QMetaType::type(t);
+
+ if (variantType == QVariant::Invalid && t == "QVariant") {
+ args << *reinterpret_cast<const QVariant(*)>(a[i+1]);
+ } else if ( variantType == 0 ){
+ qWarning("Argument %s has unknown type", t.data());
+ return id;
+ } else {
+ args << QVariant(variantType, a[i+1]);
+ }
+ }
+
+ if (returnType == QMetaType::Void) {
+ //assume we don't have parameter //TODO
+ d->endPoint->invokeRemote(metaIndex, args, returnType);
+ } else {
+ //TODO
+ qWarning() << "Cannot handle functions with return type yet.";
+ qWarning() << method.signature();
+ }
+
+
+ id-=mcount;
+ } else {
+ //TODO
+ qWarning() << "MetaCall type" << c << "not yet handled";
+ }
return id;
}
void *QServiceProxy::qt_metacast(const char* className)
{
- return 0;
+ if (!className) return 0;
+ //this object should not be castable to anything but QObject
+ return QObject::qt_metacast(className);
}
QTM_END_NAMESPACE
diff --git a/src/serviceframework/ipc/proxyobject_p.h b/src/serviceframework/ipc/proxyobject_p.h
index 646e2cc5df..d7d9156b47 100644
--- a/src/serviceframework/ipc/proxyobject_p.h
+++ b/src/serviceframework/ipc/proxyobject_p.h
@@ -43,6 +43,7 @@
#define PROXY_OBJECT_H
#include "qmobilityglobal.h"
+#include "objectendpoint_p.h"
#include <QObject>
QTM_BEGIN_NAMESPACE
@@ -52,7 +53,7 @@ class QServiceProxy : public QObject
{
//Note: Do not put Q_OBJECT here
public:
- QServiceProxy(const QByteArray& metadata, QObject* parent = 0);
+ QServiceProxy(const QByteArray& metadata, ObjectEndPoint* endpoint, QObject* parent = 0);
virtual ~QServiceProxy();
//provide custom Q_OBJECT implementation
diff --git a/src/serviceframework/ipc/qmetaobjectbuilder_p.h b/src/serviceframework/ipc/qmetaobjectbuilder_p.h
index 22176b42f9..042eec7c4c 100644
--- a/src/serviceframework/ipc/qmetaobjectbuilder_p.h
+++ b/src/serviceframework/ipc/qmetaobjectbuilder_p.h
@@ -75,7 +75,7 @@ class QMetaPropertyBuilderPrivate;
class QMetaEnumBuilder;
class QMetaEnumBuilderPrivate;
-class QMetaObjectBuilder
+class Q_AUTOTEST_EXPORT QMetaObjectBuilder
{
public:
enum AddMember
@@ -200,7 +200,7 @@ private:
friend class QMetaEnumBuilder;
};
-class QMetaMethodBuilder
+class Q_AUTOTEST_EXPORT QMetaMethodBuilder
{
public:
QMetaMethodBuilder() : _mobj(0), _index(0) {}
@@ -238,7 +238,7 @@ private:
QMetaMethodBuilderPrivate *d_func() const;
};
-class QMetaPropertyBuilder
+class Q_AUTOTEST_EXPORT QMetaPropertyBuilder
{
public:
QMetaPropertyBuilder() : _mobj(0), _index(0) {}
@@ -289,7 +289,7 @@ private:
QMetaPropertyBuilderPrivate *d_func() const;
};
-class QMetaEnumBuilder
+class Q_AUTOTEST_EXPORT QMetaEnumBuilder
{
public:
QMetaEnumBuilder() : _mobj(0), _index(0) {}
diff --git a/src/serviceframework/ipc/qservicepackage.cpp b/src/serviceframework/ipc/qservicepackage.cpp
index ebf426aa0b..45f67a159e 100644
--- a/src/serviceframework/ipc/qservicepackage.cpp
+++ b/src/serviceframework/ipc/qservicepackage.cpp
@@ -75,8 +75,8 @@ QServicePackage QServicePackage::createResponse() const
Q_ASSERT(d->responseType == QServicePackage::NotAResponse);
QServicePackage response;
response.d = new QServicePackagePrivate();
- response.d->type = d->type;
- response.d->id = d->id;
+ response.d->packageType = d->packageType;
+ response.d->messageId = d->messageId;
response.d->responseType = QServicePackage::Failed;
return response;
@@ -92,9 +92,9 @@ QDataStream &operator<<(QDataStream &out, const QServicePackage& package)
const qint8 valid = package.d ? 1 : 0;
out << (qint8) valid;
if (valid) {
- out << (qint8) package.d->type;
+ out << (qint8) package.d->packageType;
out << (qint8) package.d->responseType;
- out << package.d->id;
+ out << package.d->messageId;
out << package.d->typeId;
out << package.d->payload;
}
@@ -126,10 +126,10 @@ QDataStream &operator>>(QDataStream &in, QServicePackage& package)
}
qint8 data;
in >> data;
- package.d->type = (QServicePackage::Type) data;
+ package.d->packageType = (QServicePackage::Type) data;
in >> data;
package.d->responseType = (QServicePackage::ResponseType) data;
- in >> package.d->id;
+ in >> package.d->messageId;
in >> package.d->typeId;
in >> package.d->payload;
} else {
@@ -147,7 +147,7 @@ QDebug operator<<(QDebug dbg, const QServicePackage& p)
{
if (p.isValid()) {
QString type;
- switch(p.d->type) {
+ switch(p.d->packageType) {
case QServicePackage::SignalEmission:
type = QString("SignalEmission");
break;
@@ -162,7 +162,7 @@ QDebug operator<<(QDebug dbg, const QServicePackage& p)
}
dbg.nospace() << "QServicePackage ";
dbg.nospace() << type << " " << p.d->responseType ; dbg.space();
- dbg.nospace() << p.d->id; dbg.space();
+ dbg.nospace() << p.d->messageId; dbg.space();
dbg.nospace() << p.d->typeId;dbg.space();
} else {
dbg.nospace() << "QServicePackage(invalid)";
diff --git a/src/serviceframework/ipc/qservicepackage_p.h b/src/serviceframework/ipc/qservicepackage_p.h
index 65f6df824f..9a9165528c 100644
--- a/src/serviceframework/ipc/qservicepackage_p.h
+++ b/src/serviceframework/ipc/qservicepackage_p.h
@@ -102,22 +102,22 @@ class QServicePackagePrivate : public QSharedData
{
public:
QServicePackagePrivate()
- : type(QServicePackage::ObjectCreation),
+ : packageType(QServicePackage::ObjectCreation),
typeId(QServiceTypeIdent()), payload(QVariant()),
- id(QUuid()), responseType(QServicePackage::NotAResponse)
+ messageId(QUuid()), responseType(QServicePackage::NotAResponse)
{
}
- QServicePackage::Type type;
+ QServicePackage::Type packageType;
QServiceTypeIdent typeId;
QVariant payload;
- QUuid id;
+ QUuid messageId;
QServicePackage::ResponseType responseType;
virtual void clean()
{
- type = QServicePackage::ObjectCreation;
- id = QUuid();
+ packageType = QServicePackage::ObjectCreation;
+ messageId = QUuid();
payload = QVariant();
typeId = QServiceTypeIdent();
responseType = QServicePackage::NotAResponse;
diff --git a/src/serviceframework/qservicemanager.cpp b/src/serviceframework/qservicemanager.cpp
index 1d6b3f3659..96609cdbf3 100644
--- a/src/serviceframework/qservicemanager.cpp
+++ b/src/serviceframework/qservicemanager.cpp
@@ -411,10 +411,9 @@ QObject* QServiceManager::loadInterface(const QServiceInterfaceDescriptor& descr
.arg(descriptor.minorVersion()).toLatin1();
const QServiceTypeIdent ident(descriptor.interfaceName().toLatin1(), version);
QObject* service = QServiceControlPrivate::proxyForService(ident, location);
- if (!service) {
- qDebug() << "Cannot load remote IPC service";
+ if (!service)
d->setError(InvalidServiceLocation);
- }
+
//client owns proxy object
return service;
}
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 0d38ee31d4..62d0867414 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -9,7 +9,8 @@ contains(mobility_modules,serviceframework) {
qservicefilter \
qservicemanager \
qabstractsecuritysession \
- qservicecontext
+ qservicecontext \
+ qmetaobjectbuilder
# servicedatabase is not compiled into the serviceframework library on symbian,
# special handling is needed
diff --git a/tests/auto/qmetaobjectbuilder/qmetaobjectbuilder.pro b/tests/auto/qmetaobjectbuilder/qmetaobjectbuilder.pro
new file mode 100644
index 0000000000..4cbc03a49e
--- /dev/null
+++ b/tests/auto/qmetaobjectbuilder/qmetaobjectbuilder.pro
@@ -0,0 +1,37 @@
+TARGET = tst_qmetaobjectbuilder
+INCLUDEPATH += ../../../src/serviceframework
+INCLUDEPATH += ../../../src/serviceframework/ipc
+
+CONFIG+=testcase
+
+QT = core
+
+include(../../../common.pri)
+
+# Input
+SOURCES += tst_qmetaobjectbuilder.cpp
+
+CONFIG += mobility
+MOBILITY = serviceframework
+
+symbian|wince* {
+ symbian {
+ TARGET.CAPABILITY = ALL -TCB
+ LIBS += -lefsrv
+ }
+ wince* {
+ SFWTEST_PLUGIN_DEPLOY.sources = \
+ $$OUTPUT_DIR/build/tests/bin/plugins/tst_sfw_sampleserviceplugin.dll \
+ $$OUTPUT_DIR/build/tests/bin/plugins/tst_sfw_sampleserviceplugin2.dll \
+ $$OUTPUT_DIR/build/tests/bin/plugins/tst_sfw_testservice2plugin.dll
+ SFWTEST_PLUGIN_DEPLOY.path = plugins
+ DEPLOYMENT += SFWTEST_PLUGIN_DEPLOY
+ DEPLOYMENT_PLUGIN += qsqlite
+ }
+
+ addFiles.sources = ../../testservice2/xml/testserviceplugin.xml \
+ ../../sampleserviceplugin/xml/sampleservice.xml \
+ ../../sampleserviceplugin2/xml/sampleservice2.xml
+ addFiles.path = plugins/xmldata
+ DEPLOYMENT += addFiles
+}
diff --git a/tests/auto/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
new file mode 100644
index 0000000000..3ecb890da9
--- /dev/null
+++ b/tests/auto/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
@@ -0,0 +1,1286 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 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$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest/QtTest>
+#include <QtCore/qlocale.h>
+#include <qmetaobjectbuilder_p.h>
+
+
+QTM_USE_NAMESPACE
+
+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.
+ QCOMPARE(int(QObject::staticMetaObject.d.data[0]), 4);
+ QCOMPARE(int(staticMetaObject.d.data[0]), 4);
+}
+
+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.isDynamic());
+ 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.isDynamic());
+ 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.isDynamic());
+ 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(true);
+ prop1.setStored(true);
+ prop1.setEditable(true);
+ prop1.setUser(true);
+ prop1.setStdCppSet(true);
+ prop1.setEnumOrFlag(true);
+ prop1.setDynamic(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.isDynamic());
+ 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.isDynamic());
+
+ // 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.isDynamic());
+ 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.setDynamic(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.isDynamic() ? 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(setDynamic, isDynamic);
+
+ // 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 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));
+}
+
+// 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);
+
+
+ //copy via stream
+ QByteArray data;
+ QDataStream stream(&data, QIODevice::WriteOnly | QIODevice::Append);
+ builder3.serialize(stream);
+
+ QMetaObjectBuilder builder4;
+ QDataStream stream2(data);
+ QMap<QByteArray, const QMetaObject *> references;
+ references.insert(QByteArray("QLocale"), &QLocale::staticMetaObject);
+ builder4.deserialize(stream2, references);
+ builder4.setStaticMetacallFunction(builder.staticMetacallFunction());
+ QMetaObject *streamedMeta = builder4.toMetaObject();
+
+ QVERIFY(sameMetaObject(streamedMeta, &SomethingOfEverything::staticMetaObject));
+
+ qFree(streamedMeta);
+
+ bool ok = false;
+ QByteArray array = builder3.toRelocatableData(&ok);
+ QVERIFY(ok);
+ QMetaObject* meta1 = new QMetaObject();
+ QMetaObjectBuilder::fromRelocatableData(meta1, 0, array);
+ QVERIFY(sameMetaObject(meta1, &SomethingOfEverything::staticMetaObject));
+
+ delete meta1;
+}
+
+// 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"