Refactored the code for making the DynamicQObject testable and reusable

This commit is contained in:
cuke 2015-09-20 11:39:25 +02:00
parent 52a893577f
commit e73e37b587
15 changed files with 427 additions and 376 deletions

View File

@ -27,11 +27,21 @@ set(HEADERS_LIST
DOtherSide.h
DynamicQObject.h
IDynamicQObject.h
OnSlotExecutedHandler.h
)
set(SRC_LIST
DOtherSide.cpp
OnSlotExecutedHandler.cpp
DynamicSlot.cpp
DynamicSignal.cpp
DynamicProperty.cpp
)
# Shared version for distributing
add_library(${PROJECT_NAME} SHARED ${SRC_LIST} ${HEADERS_LIST})
target_link_libraries(${PROJECT_NAME} PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Qml Qt5::Quick)
# Static version for testing
add_library("${PROJECT_NAME}Static" STATIC ${SRC_LIST} ${HEADERS_LIST})
target_link_libraries("${PROJECT_NAME}Static" PRIVATE Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Qml Qt5::Quick)

View File

@ -15,6 +15,7 @@
#include "DynamicQObject.h"
#include "BaseQAbstractListModel.h"
#include "BaseQObject.h"
#include "OnSlotExecutedHandler.h"
void convert_to_cstring(const QString& source, char** destination)
{
@ -298,8 +299,7 @@ void dos_qobject_create(void** vptr, void* dObjectPointer, DObjectCallback dObje
{
auto dynamicQObject = new BaseQObject();
QQmlEngine::setObjectOwnership(dynamicQObject, QQmlEngine::CppOwnership);
dynamicQObject->setDObjectPointer(dObjectPointer);
dynamicQObject->setDObjectCallback(dObjectCallback);
dynamicQObject->setOnSlotExecutedHandler(OnSlotExecutedHandler(dObjectPointer, dObjectCallback));
*vptr = dynamicQObject;
}
@ -428,7 +428,7 @@ void dos_qmodelindex_sibling(void* vptr, int row, int column, void* sibling)
}
void dos_qabstractlistmodel_create(void** vptr,
void* modelObject,
void* dObjectPointer,
DObjectCallback dObjectCallback,
RowCountCallback rowCountCallback,
ColumnCountCallback columnCountCallback,
@ -438,7 +438,7 @@ void dos_qabstractlistmodel_create(void** vptr,
FlagsCallback flagsCallback,
HeaderDataCallback headerDataCallback)
{
auto model = new BaseQAbstractListModel(modelObject,
auto model = new BaseQAbstractListModel(dObjectPointer,
rowCountCallback,
columnCountCallback,
dataCallback,
@ -446,8 +446,7 @@ void dos_qabstractlistmodel_create(void** vptr,
roleNamesCallaback,
flagsCallback,
headerDataCallback);
model->setDObjectPointer(modelObject);
model->setDObjectCallback(dObjectCallback);
model->setOnSlotExecutedHandler(OnSlotExecutedHandler(dObjectPointer, dObjectCallback));
*vptr = model;
}

111
src/DynamicProperty.cpp Normal file
View File

@ -0,0 +1,111 @@
#include "DynamicProperty.h"
struct DynamicProperty::PropertyData final
{
PropertyData(const QString& name,
QMetaType::Type type,
const QString& readSlotName,
const QString& writeSlotName,
const QString& notifySignalName)
: name(name)
, type(type)
, readSlotName(readSlotName)
, writeSlotName(writeSlotName)
, notifySignalName(notifySignalName)
{}
PropertyData(const PropertyData& other)
: name(other.name)
, type(other.type)
, readSlotName(other.readSlotName)
, writeSlotName(other.writeSlotName)
, notifySignalName(other.notifySignalName)
{}
PropertyData& operator=(const PropertyData& other)
{
name = other.name;
type = other.type;
readSlotName = other.readSlotName;
writeSlotName = other.writeSlotName;
notifySignalName = other.notifySignalName;
return *this;
}
QString name;
QMetaType::Type type;
QString readSlotName;
QString writeSlotName;
QString notifySignalName;
};
DynamicProperty::DynamicProperty()
: d(nullptr)
{}
DynamicProperty::DynamicProperty(const QString& name, QMetaType::Type type, const QString& readSlotName, const QString& writeSlotName, const QString& notifySignalName)
: d(new PropertyData(name, type, readSlotName, writeSlotName, notifySignalName))
{
}
DynamicProperty::DynamicProperty(const DynamicProperty& other)
: d(nullptr)
{
if (other.d)
d.reset(new PropertyData(*other.d));
}
DynamicProperty& DynamicProperty::operator=(const DynamicProperty& other)
{
if (!other.d && d)
d.reset();
else if (other.d && !d)
d.reset(new PropertyData(*other.d));
else if (other.d && d)
*d = *other.d;
return *this;
}
DynamicProperty::~DynamicProperty()
{}
QString DynamicProperty::name() const
{
return d->name;
}
QMetaType::Type DynamicProperty::type() const
{
return d->type;
}
bool DynamicProperty::isReadable() const
{
return !d->readSlotName.isEmpty();
}
bool DynamicProperty::isWriteable() const
{
return !d->writeSlotName.isEmpty();
}
bool DynamicProperty::hasNotifySignal() const
{
return !d->notifySignalName.isEmpty();
}
QString DynamicProperty::readSlot() const
{
return d->readSlotName;
}
QString DynamicProperty::writeSlot() const
{
return d->writeSlotName;
}
QString DynamicProperty::notifySignal() const
{
return d->notifySignalName;
}

View File

@ -4,8 +4,6 @@
#include <QtCore/QString>
#include <QtCore/QMetaType>
struct PropertyData;
class DynamicProperty final
{
public:
@ -35,115 +33,6 @@ public:
QString notifySignal() const;
private:
struct PropertyData;
std::unique_ptr<PropertyData> d;
};
struct PropertyData final
{
PropertyData(const QString& name,
QMetaType::Type type,
const QString& readSlotName,
const QString& writeSlotName,
const QString& notifySignalName)
: name(name)
, type(type)
, readSlotName(readSlotName)
, writeSlotName(writeSlotName)
, notifySignalName(notifySignalName)
{}
PropertyData(const PropertyData& other)
: name(other.name)
, type(other.type)
, readSlotName(other.readSlotName)
, writeSlotName(other.writeSlotName)
, notifySignalName(other.notifySignalName)
{}
PropertyData& operator=(const PropertyData& other)
{
name = other.name;
type = other.type;
readSlotName = other.readSlotName;
writeSlotName = other.writeSlotName;
notifySignalName = other.notifySignalName;
return *this;
}
QString name;
QMetaType::Type type;
QString readSlotName;
QString writeSlotName;
QString notifySignalName;
};
DynamicProperty::DynamicProperty()
: d(nullptr)
{}
DynamicProperty::DynamicProperty(const QString& name, QMetaType::Type type, const QString& readSlotName, const QString& writeSlotName, const QString& notifySignalName)
: d(new PropertyData(name, type, readSlotName, writeSlotName, notifySignalName))
{
}
DynamicProperty::DynamicProperty(const DynamicProperty& other)
: d(nullptr)
{
if (other.d)
d.reset(new PropertyData(*other.d));
}
DynamicProperty& DynamicProperty::operator=(const DynamicProperty& other)
{
if (!other.d && d)
d.reset();
else if (other.d && !d)
d.reset(new PropertyData(*other.d));
else if (other.d && d)
*d = *other.d;
return *this;
}
DynamicProperty::~DynamicProperty()
{}
QString DynamicProperty::name() const
{
return d->name;
}
QMetaType::Type DynamicProperty::type() const
{
return d->type;
}
bool DynamicProperty::isReadable() const
{
return !d->readSlotName.isEmpty();
}
bool DynamicProperty::isWriteable() const
{
return !d->writeSlotName.isEmpty();
}
bool DynamicProperty::hasNotifySignal() const
{
return !d->notifySignalName.isEmpty();
}
QString DynamicProperty::readSlot() const
{
return d->readSlotName;
}
QString DynamicProperty::writeSlot() const
{
return d->writeSlotName;
}
QString DynamicProperty::notifySignal() const
{
return d->notifySignalName;
}

View File

@ -17,6 +17,7 @@ template <class T>
class DynamicQObject : public T, public IDynamicQObject
{
using SafeQMetaObjectPtr = std::unique_ptr<QMetaObject, void(*)(void*)>;
using OnSlotExecutedHandler = std::function<QVariant(const DynamicSlot&, const std::vector<QVariant>&)>;
public:
/// Constructor
@ -25,11 +26,8 @@ public:
/// Destructor
virtual ~DynamicQObject();
/// Sets the function to be called from C++ to D or Nimrod
void setDObjectCallback(IDynamicQObject::Callback callback) override;
/// Sets the D or Nimrod object that owns this DynamicQObject
void setDObjectPointer(void* dObjectPointer) override;
/// Sets the on slot executed handler
void setOnSlotExecutedHandler(const OnSlotExecutedHandler& handler);
/// Register a new signal
bool registerSignal(const QString& name,
@ -61,8 +59,6 @@ public:
private:
bool executeSlot(const DynamicSlot& slot, void** args);
QVariant executeSlot(const DynamicSlot& slot, const std::vector<QVariant> &args);
bool readProperty(const DynamicProperty& property, void** args);
bool writeProperty(const DynamicProperty& property, void** args);
@ -81,16 +77,13 @@ private:
QHash<QString, DynamicSlot> m_slotsByName;
QHash<QByteArray, DynamicSlot> m_slotsBySignature;
QHash<QByteArray, DynamicProperty> m_propertiesByName;
void* m_dObjectPointer;
IDynamicQObject::Callback m_dObjectCallback;
OnSlotExecutedHandler m_onSlotExecutedHandler;
};
template <typename T>
DynamicQObject<T>::DynamicQObject()
: T()
, m_metaObject(nullptr, ::free)
, m_dObjectPointer(nullptr)
, m_dObjectCallback(nullptr)
{
QMetaObjectBuilder builder;
builder.setFlags(QMetaObjectBuilder::DynamicMetaObject);
@ -100,15 +93,9 @@ DynamicQObject<T>::DynamicQObject()
}
template <typename T>
void DynamicQObject<T>::setDObjectCallback(IDynamicQObject::Callback callback)
void DynamicQObject<T>::setOnSlotExecutedHandler(const DynamicQObject::OnSlotExecutedHandler &handler)
{
m_dObjectCallback = callback;
}
template <typename T>
void DynamicQObject<T>::setDObjectPointer(void* dObjectPointer)
{
m_dObjectPointer = dObjectPointer;
m_onSlotExecutedHandler = handler;
}
template <typename T>
@ -284,15 +271,12 @@ bool DynamicQObject<T>::executeSlot(const DynamicSlot& slot, void** args)
if (!slot.isValid())
return false;
if (!m_dObjectCallback || !m_dObjectPointer)
return false;
std::vector<QVariant> arguments;
arguments.reserve(slot.argumentsTypes().size());
for (int i = 0; i < slot.argumentsTypes().count(); ++i)
arguments.emplace_back(QVariant(slot.argumentTypeAt(i), args[i + 1]));
QVariant result = executeSlot(slot, arguments);
QVariant result = m_onSlotExecutedHandler(slot, arguments);
if (slot.returnType() != QMetaType::Void && result.isValid())
{
@ -303,30 +287,6 @@ bool DynamicQObject<T>::executeSlot(const DynamicSlot& slot, void** args)
return true;
}
template <typename T>
QVariant DynamicQObject<T>::executeSlot(const DynamicSlot& slot, const std::vector<QVariant>& args)
{
QVariant result;
if (!m_dObjectCallback || !m_dObjectPointer)
return result;
// prepare slot name
QVariant slotName(slot.name());
// prepare void* for the QVariants
std::vector<void*> argumentsAsVoidPointers;
argumentsAsVoidPointers.reserve(args.size() + 1);
argumentsAsVoidPointers.emplace_back(&result);
for (size_t i = 0; i < args.size(); ++i)
argumentsAsVoidPointers.emplace_back((void*)(&args[i]));
// send them to the binding handler
m_dObjectCallback(m_dObjectPointer, &slotName, argumentsAsVoidPointers.size(), &argumentsAsVoidPointers[0]);
return result;
}
template <typename T>
bool DynamicQObject<T>::readProperty(const DynamicProperty& property, void** args)
{
@ -370,8 +330,10 @@ bool DynamicQObject<T>::writeProperty(const DynamicProperty& property, void** ar
if (writeSlot.returnType() != QMetaType::Void)
return false;
QVariant newValue(writeSlot.argumentTypeAt(0), args[0]);
executeSlot(writeSlot, {newValue});
void* sortedArgs[2]; // The write property is peculiar because it has
sortedArgs[0] = args[2]; // the actual value in pos 0 and result in 2
sortedArgs[1] = args[0]; // We reorder it for having the result in 0 and
executeSlot(writeSlot, sortedArgs); // first arg in 1
return true;
}

89
src/DynamicSignal.cpp Normal file
View File

@ -0,0 +1,89 @@
#include "DynamicSignal.h"
struct DynamicSignal::SignalData
{
QString name;
QList<QMetaType::Type> argumentsTypes;
QByteArray signature;
};
DynamicSignal::DynamicSignal()
: d(nullptr)
{
}
DynamicSignal::DynamicSignal(const QString& name, const QList<QMetaType::Type>& arguments)
: d(new SignalData())
{
d->name = name;
d->signature = QByteArray();
d->argumentsTypes = arguments;
_initSignature();
}
DynamicSignal::DynamicSignal(const DynamicSignal& signal)
{
if (signal.isValid())
{
d.reset(new SignalData());
*d = *signal.d;
}
else
d.reset(nullptr);
}
DynamicSignal& DynamicSignal::operator=(const DynamicSignal& signal)
{
if (signal.isValid())
{
d.reset(new SignalData());
*d = *signal.d;
}
else
d.reset(nullptr);
return *this;
}
DynamicSignal::~DynamicSignal()
{
}
bool DynamicSignal::isValid() const
{
return d != nullptr;
}
QString DynamicSignal::name() const
{
return isValid() ? d->name : QString();
}
QByteArray DynamicSignal::signature() const
{
return isValid() ? d->signature : QByteArray();
}
bool DynamicSignal::validate(const QVariantList& arguments)
{
// TODO: here we should test if the given arguments
// match this signal signature
// This is important because a class could have multiple
// signals with the same name but different arguments
Q_UNUSED(arguments);
return true;
}
void DynamicSignal::_initSignature()
{
QString signature("%1(%2)");
QString arguments;
for (int i = 0; i < d->argumentsTypes.size(); ++i)
{
if (i != 0)
arguments += ',';
arguments += QMetaType::typeName(d->argumentsTypes[i]);
}
d->signature = signature.arg(d->name, arguments).toUtf8();
}

View File

@ -7,8 +7,6 @@
#include <QtCore/QMetaType>
#include <QtCore/QList>
struct SignalData;
class DynamicSignal final
{
public:
@ -28,93 +26,6 @@ public:
private:
void _initSignature();
struct SignalData;
std::unique_ptr<SignalData> d;
};
struct SignalData
{
QString name;
QList<QMetaType::Type> argumentsTypes;
QByteArray signature;
};
DynamicSignal::DynamicSignal()
: d(nullptr)
{
}
DynamicSignal::DynamicSignal(const QString& name, const QList<QMetaType::Type>& arguments)
: d(new SignalData())
{
d->name = name;
d->signature = QByteArray();
d->argumentsTypes = arguments;
_initSignature();
}
DynamicSignal::DynamicSignal(const DynamicSignal& signal)
{
if (signal.isValid())
{
d.reset(new SignalData());
*d = *signal.d;
}
else
d.reset(nullptr);
}
DynamicSignal& DynamicSignal::operator=(const DynamicSignal& signal)
{
if (signal.isValid())
{
d.reset(new SignalData());
*d = *signal.d;
}
else
d.reset(nullptr);
return *this;
}
DynamicSignal::~DynamicSignal()
{
}
bool DynamicSignal::isValid() const
{
return d != nullptr;
}
QString DynamicSignal::name() const
{
return isValid() ? d->name : QString();
}
QByteArray DynamicSignal::signature() const
{
return isValid() ? d->signature : QByteArray();
}
bool DynamicSignal::validate(const QVariantList& arguments)
{
// TODO: here we should test if the given arguments
// match this signal signature
// This is important because a class could have multiple
// signals with the same name but different arguments
Q_UNUSED(arguments);
return true;
}
void DynamicSignal::_initSignature()
{
QString signature("%1(%2)");
QString arguments;
for (int i = 0; i < d->argumentsTypes.size(); ++i)
{
if (i != 0)
arguments += ',';
arguments += QMetaType::typeName(d->argumentsTypes[i]);
}
d->signature = signature.arg(d->name, arguments).toUtf8();
}

96
src/DynamicSlot.cpp Normal file
View File

@ -0,0 +1,96 @@
#include "DynamicSlot.h"
struct DynamicSlot::SlotData
{
QString name;
QMetaType::Type returnType;
QList<QMetaType::Type> argumentsTypes;
QByteArray signature;
};
DynamicSlot::DynamicSlot()
: d(nullptr)
{}
DynamicSlot::DynamicSlot(const QString& name,
QMetaType::Type returnType,
const QList<QMetaType::Type>& argumentsTypes)
: d(new SlotData())
{
d->name = name;
d->returnType = returnType;
d->argumentsTypes = argumentsTypes;
_initSignature();
}
DynamicSlot::DynamicSlot(const DynamicSlot& slot)
{
if (slot.isValid())
{
d.reset(new SlotData());
*d = *slot.d;
}
else
d.reset(nullptr);
}
DynamicSlot& DynamicSlot::operator=(const DynamicSlot& slot)
{
if (slot.isValid())
{
d.reset(new SlotData());
*d = *slot.d;
}
else
d.reset(nullptr);
return *this;
}
DynamicSlot::~DynamicSlot()
{
}
QString DynamicSlot::name() const
{
return isValid() ? d->name : QString();
}
bool DynamicSlot::isValid() const
{
return d != nullptr;
}
QByteArray DynamicSlot::signature() const
{
return isValid() ? d->signature : QByteArray();
}
QMetaType::Type DynamicSlot::returnType() const
{
return isValid() ? d->returnType : QMetaType::UnknownType;
}
QList<QMetaType::Type> DynamicSlot::argumentsTypes() const
{
return isValid() ? d->argumentsTypes : QList<QMetaType::Type>();
}
QMetaType::Type DynamicSlot::argumentTypeAt(int i) const
{
return isValid() ? d->argumentsTypes.at(i) : QMetaType::UnknownType;
}
void DynamicSlot::_initSignature()
{
QString signature("%1(%2)");
QString arguments = "";
for (int i = 0; i < d->argumentsTypes.size(); ++i)
{
if (i != 0)
arguments += ',';
arguments += QMetaType::typeName(d->argumentsTypes[i]);
}
d->signature = signature.arg(d->name, arguments).toUtf8();
}

View File

@ -13,7 +13,6 @@
#include "private/qmetaobjectbuilder_p.h"
struct SlotData;
class QString;
class DynamicSlot final
@ -37,102 +36,6 @@ public:
private:
void _initSignature();
struct SlotData;
std::unique_ptr<SlotData> d;
};
struct SlotData
{
QString name;
QMetaType::Type returnType;
QList<QMetaType::Type> argumentsTypes;
QByteArray signature;
};
DynamicSlot::DynamicSlot()
: d(nullptr)
{
}
DynamicSlot::DynamicSlot(const QString& name,
QMetaType::Type returnType,
const QList<QMetaType::Type>& argumentsTypes)
: d(new SlotData())
{
d->name = name;
d->returnType = returnType;
d->argumentsTypes = argumentsTypes;
_initSignature();
}
DynamicSlot::DynamicSlot(const DynamicSlot& slot)
{
if (slot.isValid())
{
d.reset(new SlotData());
*d = *slot.d;
}
else
d.reset(nullptr);
}
DynamicSlot& DynamicSlot::operator=(const DynamicSlot& slot)
{
if (slot.isValid())
{
d.reset(new SlotData());
*d = *slot.d;
}
else
d.reset(nullptr);
return *this;
}
DynamicSlot::~DynamicSlot()
{
}
QString DynamicSlot::name() const
{
return isValid() ? d->name : QString();
}
bool DynamicSlot::isValid() const
{
return d != nullptr;
}
QByteArray DynamicSlot::signature() const
{
return isValid() ? d->signature : QByteArray();
}
QMetaType::Type DynamicSlot::returnType() const
{
return isValid() ? d->returnType : QMetaType::UnknownType;
}
QList<QMetaType::Type> DynamicSlot::argumentsTypes() const
{
return isValid() ? d->argumentsTypes : QList<QMetaType::Type>();
}
QMetaType::Type DynamicSlot::argumentTypeAt(int i) const
{
return isValid() ? d->argumentsTypes.at(i) : QMetaType::UnknownType;
}
void DynamicSlot::_initSignature()
{
QString signature("%1(%2)");
QString arguments = "";
for (int i = 0; i < d->argumentsTypes.size(); ++i)
{
if (i != 0)
arguments += ',';
arguments += QMetaType::typeName(d->argumentsTypes[i]);
}
d->signature = signature.arg(d->name, arguments).toUtf8();
}

View File

@ -8,12 +8,6 @@ public:
/// Destructor
virtual ~IDynamicQObject() = default;
/// Sets the function to be called from C++ to D or Nimrod
virtual void setDObjectCallback(Callback callback) = 0;
/// Sets the D or Nimrod object that owns this DynamicQObject
virtual void setDObjectPointer(void* dObjectPointer) = 0;
/// Register a new signal
virtual bool registerSignal(const QString& name,
const QList<QMetaType::Type>& argumentsTypes,

View File

@ -0,0 +1,31 @@
#include "OnSlotExecutedHandler.h"
#include "DynamicSlot.h"
OnSlotExecutedHandler::OnSlotExecutedHandler(void *dObjectPointer,
IDynamicQObject::Callback dObjectCallback)
: m_dObjectPointer(dObjectPointer)
, m_dObjectCallback(dObjectCallback)
{}
QVariant OnSlotExecutedHandler::operator()(const DynamicSlot& slot, const std::vector<QVariant> &args)
{
QVariant result;
if (!m_dObjectCallback || !m_dObjectPointer)
return result;
// prepare slot name
QVariant slotName(slot.name());
// prepare void* for the QVariants
std::vector<void*> argumentsAsVoidPointers;
argumentsAsVoidPointers.reserve(args.size() + 1);
argumentsAsVoidPointers.emplace_back(&result);
for (size_t i = 0; i < args.size(); ++i)
argumentsAsVoidPointers.emplace_back((void*)(&args[i]));
// send them to the binding handler
m_dObjectCallback(m_dObjectPointer, &slotName, argumentsAsVoidPointers.size(), &argumentsAsVoidPointers[0]);
return result;
}

View File

@ -0,0 +1,19 @@
#pragma once
#include <QVariant>
#include <vector>
#include "IDynamicQObject.h"
class DynamicSlot;
class OnSlotExecutedHandler
{
public:
OnSlotExecutedHandler(void* dObjectPointer, IDynamicQObject::Callback dObjectCallback);
QVariant operator()(const DynamicSlot& slot, std::vector<QVariant> const& args);
private:
void* m_dObjectPointer;
IDynamicQObject::Callback m_dObjectCallback;
};

View File

@ -11,4 +11,4 @@ find_package(Qt5Test REQUIRED)
add_executable(${PROJECT_NAME} test_dynamicqobject.cpp)
target_link_libraries(${PROJECT_NAME} Qt5::Test)
target_link_libraries(${PROJECT_NAME} DOtherSideStatic Qt5::Test)

View File

@ -1,7 +1,22 @@
#include <QTest>
#include <QSignalSpy>
#include <tuple>
#include <iostream>
#include <QDebug>
#include "../src/BaseQObject.h"
#include "../src/DynamicQObject.h"
// Templates that convers a T to a string
template <typename T>
struct TypeName
{
static const char* Get() { return typeid(T).name(); }
};
template <> struct TypeName<int> { static const char* Get() { return "int"; } };
template <> struct TypeName<QString> { static const char* Get() { return "QString"; } };
template <> struct TypeName<bool> { static const char* Get() { return "bool"; } };
template <> struct TypeName<QVariant> { static const char* Get() { return "QVariant"; } };
class TestDynamicQObject : public QObject
{
Q_OBJECT
@ -9,6 +24,7 @@ class TestDynamicQObject : public QObject
private slots:
void memoryLeakTest() {
DynamicQObject<QObject> dynamicQObject;
BaseQObject baseQObject;
}
void testRegisterSignal() {
@ -22,11 +38,11 @@ private slots:
QCOMPARE(signalSpy.count(), 1);
}
void testRegisterSlot() {
DynamicQObject<QObject> dynamicQObject;
int index;
dynamicQObject.registerSlot("fooSlot", QMetaType::Void, {}, index);
QCOMPARE(index != -1, true);
void testSlotExecution() {
testSlotExecutionForType<int>(10);
testSlotExecutionForType<QString>("foo");
testSlotExecutionForType<bool>(false);
testSlotExecutionForType<QVariant>(QVariant(40));
}
void testRegisterProperty() {
@ -45,6 +61,27 @@ private slots:
result = dynamicQObject.registerProperty("foo", QMetaType::Int, "foo", "setFoo", "fooChanged");
QCOMPARE(result, true);
}
private:
template<typename ReturnType>
void testSlotExecutionForType(ReturnType expectedReturnValue) {
DynamicQObject<QObject> dynamicQObject;
int index;
dynamicQObject.registerSlot("fooSlot", (QMetaType::Type)qMetaTypeId<ReturnType>(), {}, index);
QCOMPARE(index != -1, true);
// Call the slot and check return value
bool called = false;
auto handler = [&called, expectedReturnValue](const DynamicSlot &slot, const std::vector<QVariant> &args) -> QVariant {
called = true;
return expectedReturnValue;
};
dynamicQObject.setOnSlotExecutedHandler(handler);
ReturnType result;
QMetaObject::invokeMethod(&dynamicQObject, "fooSlot", QReturnArgument<ReturnType>(TypeName<ReturnType>::Get(), result));
QCOMPARE(called, true);
QCOMPARE(result, expectedReturnValue);
}
};
QTEST_MAIN(TestDynamicQObject)