15 changed files with 465 additions and 3 deletions
@ -1,4 +1,8 @@ |
|||||
TEMPLATE = subdirs |
TEMPLATE = subdirs |
||||
|
|
||||
SUBDIRS += \ |
SUBDIRS += \ |
||||
settingsgenerator |
settingsgenerator \ |
||||
|
serviceregistry \ |
||||
|
serviceregistrytestplugin |
||||
|
|
||||
|
serviceregistry.depends += serviceregistrytestplugin |
||||
|
@ -0,0 +1,19 @@ |
|||||
|
#ifndef PLUGINTESTINTERFACE_H |
||||
|
#define PLUGINTESTINTERFACE_H |
||||
|
|
||||
|
#include <QtCore/QObject> |
||||
|
|
||||
|
class PluginTestInterface |
||||
|
{ |
||||
|
Q_DISABLE_COPY(PluginTestInterface) |
||||
|
public: |
||||
|
inline PluginTestInterface() = default; |
||||
|
virtual inline ~PluginTestInterface() = default; |
||||
|
|
||||
|
virtual int magicNumber() const = 0; |
||||
|
}; |
||||
|
|
||||
|
#define PluginTestInterfaceIId "de.skycoder42.qtmvvm.core.tests.PluginTestInterface" |
||||
|
Q_DECLARE_INTERFACE(PluginTestInterface, PluginTestInterfaceIId) |
||||
|
|
||||
|
#endif // PLUGINTESTINTERFACE_H
|
@ -0,0 +1,22 @@ |
|||||
|
TEMPLATE = app |
||||
|
|
||||
|
QT += testlib mvvmcore |
||||
|
QT -= gui |
||||
|
CONFIG += console |
||||
|
CONFIG -= app_bundle |
||||
|
|
||||
|
TARGET = tst_serviceregistry |
||||
|
|
||||
|
SOURCES += \ |
||||
|
tst_serviceregistry.cpp \ |
||||
|
testservice.cpp \ |
||||
|
testobject.cpp |
||||
|
|
||||
|
HEADERS += \ |
||||
|
testinterface.h \ |
||||
|
testservice.h \ |
||||
|
testobject.h \ |
||||
|
plugintestinterface.h |
||||
|
|
||||
|
load(qt_build_paths) |
||||
|
DEFINES += PLUGIN_TESTDIR=\\\"$$MODULE_BASE_OUTDIR/tests/plugins\\\" |
@ -0,0 +1,17 @@ |
|||||
|
#ifndef TESTINTERFACE_H |
||||
|
#define TESTINTERFACE_H |
||||
|
|
||||
|
#include <QtCore/QObject> |
||||
|
|
||||
|
class TestInterface |
||||
|
{ |
||||
|
Q_DISABLE_COPY(TestInterface) |
||||
|
public: |
||||
|
inline TestInterface() = default; |
||||
|
virtual inline ~TestInterface() = default; |
||||
|
}; |
||||
|
|
||||
|
#define TestInterfaceIId "de.skycoder42.qtmvvm.core.tests.TestInterface" |
||||
|
Q_DECLARE_INTERFACE(TestInterface, TestInterfaceIId) |
||||
|
|
||||
|
#endif // TESTINTERFACE_H
|
@ -0,0 +1 @@ |
|||||
|
#include "testobject.h" |
@ -0,0 +1,56 @@ |
|||||
|
#ifndef TESTOBJECT_H |
||||
|
#define TESTOBJECT_H |
||||
|
|
||||
|
#include <QtCore/QObject> |
||||
|
#include <QtCore/QSharedPointer> |
||||
|
#include <QtMvvmCore/Injection> |
||||
|
|
||||
|
#define CREATE_TEST_OBJECT(index, ...) \ |
||||
|
class TestObject ## index : public QObject \ |
||||
|
{ \ |
||||
|
Q_OBJECT \ |
||||
|
\ |
||||
|
public: \ |
||||
|
__VA_ARGS__ \ |
||||
|
\ |
||||
|
Q_INVOKABLE explicit inline TestObject ## index(QObject *parent = nullptr) : \ |
||||
|
QObject{parent} \ |
||||
|
{} \ |
||||
|
}; |
||||
|
|
||||
|
#define DEP(index) \ |
||||
|
TestObject ## index *dep = nullptr; \ |
||||
|
QTMVVM_INJECT_PROP(TestObject ## index *, dep, dep) |
||||
|
|
||||
|
#define DESTROYER \ |
||||
|
QSharedPointer<TestObject0> holder; |
||||
|
|
||||
|
#define SOMETIME_DESTROYER(index) \ |
||||
|
DESTROYER \ |
||||
|
inline ~TestObject ## index() { qDebug(Q_FUNC_INFO); } |
||||
|
|
||||
|
#define NEVER_DESTROYER(index) \ |
||||
|
DESTROYER \ |
||||
|
inline ~TestObject ## index() { Q_ASSERT_X(false, Q_FUNC_INFO, "destructor of never-destroy-object called"); } |
||||
|
|
||||
|
CREATE_TEST_OBJECT(0) |
||||
|
|
||||
|
CREATE_TEST_OBJECT(1, int data = 42;) |
||||
|
CREATE_TEST_OBJECT(2, int data = 42;) |
||||
|
CREATE_TEST_OBJECT(3, int data = 42;) |
||||
|
|
||||
|
CREATE_TEST_OBJECT(4) |
||||
|
CREATE_TEST_OBJECT(5) |
||||
|
CREATE_TEST_OBJECT(6, DEP(4)) |
||||
|
CREATE_TEST_OBJECT(7, DEP(5)) |
||||
|
CREATE_TEST_OBJECT(8, bool hasBoth = false;) |
||||
|
|
||||
|
CREATE_TEST_OBJECT(9, DEP(0)) |
||||
|
CREATE_TEST_OBJECT(10, DEP(9)) |
||||
|
|
||||
|
CREATE_TEST_OBJECT(11, SOMETIME_DESTROYER(11)) |
||||
|
CREATE_TEST_OBJECT(12, SOMETIME_DESTROYER(12)) |
||||
|
CREATE_TEST_OBJECT(13, SOMETIME_DESTROYER(13)) |
||||
|
CREATE_TEST_OBJECT(14, NEVER_DESTROYER(14)) |
||||
|
|
||||
|
#endif // TESTOBJECT_H
|
@ -0,0 +1,9 @@ |
|||||
|
#include "testservice.h" |
||||
|
|
||||
|
TestService::TestService(QObject *parent) : |
||||
|
QObject{parent} |
||||
|
{} |
||||
|
|
||||
|
WeakTestService::WeakTestService(QObject *parent) : |
||||
|
TestService{parent} |
||||
|
{} |
@ -0,0 +1,24 @@ |
|||||
|
#ifndef TESTSERVICE_H |
||||
|
#define TESTSERVICE_H |
||||
|
|
||||
|
#include <QtCore/QObject> |
||||
|
#include "testinterface.h" |
||||
|
|
||||
|
class TestService : public QObject, public TestInterface |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
Q_INTERFACES(TestInterface) |
||||
|
|
||||
|
public: |
||||
|
Q_INVOKABLE explicit TestService(QObject *parent = nullptr); |
||||
|
}; |
||||
|
|
||||
|
class WeakTestService : public TestService |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
|
||||
|
public: |
||||
|
Q_INVOKABLE explicit WeakTestService(QObject *parent = nullptr); |
||||
|
}; |
||||
|
|
||||
|
#endif // TESTSERVICE_H
|
@ -0,0 +1,262 @@ |
|||||
|
#include <QString> |
||||
|
#include <QtTest> |
||||
|
#include <QCoreApplication> |
||||
|
#include <QtMvvmCore/ServiceRegistry> |
||||
|
|
||||
|
#include "testinterface.h" |
||||
|
#include "testservice.h" |
||||
|
#include "testobject.h" |
||||
|
#include "plugintestinterface.h" |
||||
|
using namespace QtMvvm; |
||||
|
|
||||
|
class ServiceRegistryTest : public QObject |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
|
||||
|
private Q_SLOTS: |
||||
|
void testRegistrations(); |
||||
|
void testPlainConstructions(); |
||||
|
void testDepedencyConstructions(); |
||||
|
void testInjection(); |
||||
|
|
||||
|
void testPluginRegistration(); |
||||
|
|
||||
|
void testDestructionScopes(); |
||||
|
|
||||
|
public: |
||||
|
static QWeakPointer<TestObject0> weak0; |
||||
|
static QWeakPointer<TestObject0> weak1; |
||||
|
static QWeakPointer<TestObject0> weak2; |
||||
|
static QWeakPointer<TestObject0> weak3; |
||||
|
}; |
||||
|
|
||||
|
QWeakPointer<TestObject0> ServiceRegistryTest::weak0; |
||||
|
QWeakPointer<TestObject0> ServiceRegistryTest::weak1; |
||||
|
QWeakPointer<TestObject0> ServiceRegistryTest::weak2; |
||||
|
QWeakPointer<TestObject0 >ServiceRegistryTest::weak3; |
||||
|
|
||||
|
void ServiceRegistryTest::testRegistrations() |
||||
|
{ |
||||
|
try { |
||||
|
QVERIFY(!ServiceRegistry::instance()->isRegistered<TestInterface>()); |
||||
|
QVERIFY(!ServiceRegistry::instance()->isRegistered<TestService>()); |
||||
|
QVERIFY(!ServiceRegistry::instance()->isRegistered<TestObject0>()); |
||||
|
QVERIFY_EXCEPTION_THROWN(ServiceRegistry::instance()->service<TestInterface>(), ServiceDependencyException); |
||||
|
QVERIFY_EXCEPTION_THROWN(ServiceRegistry::instance()->service<TestObject0>(), ServiceDependencyException); |
||||
|
|
||||
|
//register service
|
||||
|
ServiceRegistry::instance()->registerInterface<TestInterface, WeakTestService>(ServiceRegistry::DestroyOnAppDestroy, true); |
||||
|
QVERIFY(ServiceRegistry::instance()->isRegistered<TestInterface>()); |
||||
|
QVERIFY(ServiceRegistry::instance()->isRegistered(TestInterfaceIId)); |
||||
|
QVERIFY(!ServiceRegistry::instance()->isRegistered<WeakTestService>()); |
||||
|
QVERIFY(!ServiceRegistry::instance()->isRegistered<TestService>()); |
||||
|
|
||||
|
ServiceRegistry::instance()->registerInterface<TestInterface, TestService>(); |
||||
|
QVERIFY(ServiceRegistry::instance()->isRegistered<TestInterface>()); |
||||
|
QVERIFY(!ServiceRegistry::instance()->isRegistered<TestService>()); |
||||
|
#define TMP_REGISTER ServiceRegistry::instance()->registerInterface<TestInterface, WeakTestService>() |
||||
|
QVERIFY_EXCEPTION_THROWN(TMP_REGISTER, ServiceExistsException); |
||||
|
#undef TMP_REGISTER |
||||
|
|
||||
|
QVERIFY(ServiceRegistry::instance()->service<TestInterface>()); |
||||
|
QVERIFY(ServiceRegistry::instance()->serviceObj(TestInterfaceIId)); |
||||
|
QVERIFY(dynamic_cast<TestService*>(ServiceRegistry::instance()->service<TestInterface>())); |
||||
|
|
||||
|
//register object
|
||||
|
ServiceRegistry::instance()->registerObject<TestObject0>(); |
||||
|
QVERIFY(ServiceRegistry::instance()->isRegistered<TestObject0>()); |
||||
|
QVERIFY(ServiceRegistry::instance()->service<TestObject0>()); |
||||
|
} catch(QException &e) { |
||||
|
QFAIL(e.what()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void ServiceRegistryTest::testPlainConstructions() |
||||
|
{ |
||||
|
try { |
||||
|
// test default (meta) construction
|
||||
|
ServiceRegistry::instance()->registerObject<TestObject1>(); |
||||
|
auto obj1 = ServiceRegistry::instance()->service<TestObject1>(); |
||||
|
QVERIFY(obj1); |
||||
|
QCOMPARE(obj1->data, 42); |
||||
|
|
||||
|
// test function construction
|
||||
|
ServiceRegistry::instance()->registerObject<TestObject2>([](){ |
||||
|
auto obj = new TestObject2{}; |
||||
|
obj->data = 13; |
||||
|
return obj; |
||||
|
}); |
||||
|
auto obj2 = ServiceRegistry::instance()->service<TestObject2>(); |
||||
|
QVERIFY(obj2); |
||||
|
QCOMPARE(obj2->data, 13); |
||||
|
|
||||
|
// test instance construction
|
||||
|
auto obj3Instance = new TestObject3{}; |
||||
|
ServiceRegistry::instance()->registerObject(obj3Instance); |
||||
|
auto obj3 = ServiceRegistry::instance()->service<TestObject3>(); |
||||
|
QCOMPARE(obj3, obj3Instance); |
||||
|
} catch(QException &e) { |
||||
|
QFAIL(e.what()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void ServiceRegistryTest::testDepedencyConstructions() |
||||
|
{ |
||||
|
try { |
||||
|
//try valid (inverse order must work)
|
||||
|
ServiceRegistry::instance()->registerObject<TestObject6>(); |
||||
|
ServiceRegistry::instance()->registerObject<TestObject4>(); |
||||
|
auto obj = ServiceRegistry::instance()->service<TestObject6>(); |
||||
|
QVERIFY(obj); |
||||
|
QVERIFY(obj->dep); |
||||
|
|
||||
|
//try without dep
|
||||
|
ServiceRegistry::instance()->registerObject<TestObject7>(); |
||||
|
QVERIFY_EXCEPTION_THROWN(ServiceRegistry::instance()->service<TestObject7>(), ServiceDependencyException); |
||||
|
ServiceRegistry::instance()->registerObject<TestObject5>(); |
||||
|
QVERIFY(ServiceRegistry::instance()->service<TestObject7>()); |
||||
|
|
||||
|
// try with fn
|
||||
|
ServiceRegistry::instance()->registerObject<TestObject8>([](TestObject6 *obj1, TestObject0 *obj2){ |
||||
|
auto retObj = new TestObject8{}; |
||||
|
retObj->hasBoth = obj1 && obj2; |
||||
|
return retObj; |
||||
|
}); |
||||
|
auto fnObj = ServiceRegistry::instance()->service<TestObject8>(); |
||||
|
QVERIFY(fnObj); |
||||
|
QVERIFY(fnObj->hasBoth); |
||||
|
} catch(QException &e) { |
||||
|
QFAIL(e.what()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void ServiceRegistryTest::testInjection() |
||||
|
{ |
||||
|
try { |
||||
|
// try normal injection
|
||||
|
auto obj1 = new TestObject9{this}; |
||||
|
QVERIFY(!obj1->dep); |
||||
|
ServiceRegistry::instance()->injectServices(obj1); |
||||
|
QVERIFY(obj1->dep); |
||||
|
obj1->deleteLater(); |
||||
|
|
||||
|
//try construct injection
|
||||
|
auto obj2 = ServiceRegistry::instance()->constructInjected<TestObject9>(this); |
||||
|
QVERIFY(obj2); |
||||
|
QVERIFY(obj2->dep); |
||||
|
obj2->deleteLater(); |
||||
|
|
||||
|
//try invalid injection
|
||||
|
QVERIFY_EXCEPTION_THROWN(ServiceRegistry::instance()->constructInjected<TestObject10>(this), ServiceDependencyException); |
||||
|
auto obj3 = new TestObject10{this}; |
||||
|
QVERIFY_EXCEPTION_THROWN(ServiceRegistry::instance()->injectServices(obj3), ServiceDependencyException); |
||||
|
obj3->deleteLater(); |
||||
|
} catch(QException &e) { |
||||
|
QFAIL(e.what()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void ServiceRegistryTest::testPluginRegistration() |
||||
|
{ |
||||
|
try { |
||||
|
#ifdef Q_OS_LINUX |
||||
|
QVERIFY(QFile::exists(QStringLiteral(PLUGIN_TESTDIR "/serviceregistry/libserviceregistry_testplugin.so"))); |
||||
|
#elif defined(Q_OS_DARWIN) |
||||
|
QVERIFY(QFile::exists(QStringLiteral(PLUGIN_TESTDIR "/serviceregistry/libserviceregistry_testplugin.dylib"))); |
||||
|
QVERIFY(QFile::exists(QStringLiteral(PLUGIN_TESTDIR "/serviceregistry/libserviceregistry_testplugin_debug.dylib"))); |
||||
|
#elif defined(Q_OS_WIN) |
||||
|
QVERIFY(QFile::exists(QStringLiteral(PLUGIN_TESTDIR "/serviceregistry/libserviceregistry_testplugin.dll"))); |
||||
|
QVERIFY(QFile::exists(QStringLiteral(PLUGIN_TESTDIR "/serviceregistry/libserviceregistry_testplugind.dll"))); |
||||
|
#endif |
||||
|
|
||||
|
qputenv("QT_PLUGIN_PATH", PLUGIN_TESTDIR); |
||||
|
ServiceRegistry::instance()->registerPlugin<PluginTestInterface>(QStringLiteral("serviceregistry"), QStringLiteral("test2")); |
||||
|
QVERIFY(ServiceRegistry::instance()->isRegistered<PluginTestInterface>()); |
||||
|
QVERIFY(ServiceRegistry::instance()->service<PluginTestInterface>()); |
||||
|
QCOMPARE(ServiceRegistry::instance()->service<PluginTestInterface>()->magicNumber(), 72); |
||||
|
} catch(QException &e) { |
||||
|
QFAIL(e.what()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void ServiceRegistryTest::testDestructionScopes() |
||||
|
{ |
||||
|
try { |
||||
|
{ |
||||
|
auto holder0 = QSharedPointer<TestObject0>::create(); |
||||
|
auto holder1 = QSharedPointer<TestObject0>::create(); |
||||
|
auto holder2 = QSharedPointer<TestObject0>::create(); |
||||
|
auto holder3 = QSharedPointer<TestObject0>::create(); |
||||
|
|
||||
|
weak0 = holder0; |
||||
|
weak1 = holder1; |
||||
|
weak2 = holder2; |
||||
|
weak3 = holder3; |
||||
|
|
||||
|
//register and create all destruction instances
|
||||
|
ServiceRegistry::instance()->registerObject<TestObject11>(ServiceRegistry::DestroyOnAppQuit); |
||||
|
QVERIFY(ServiceRegistry::instance()->service<TestObject11>()); |
||||
|
ServiceRegistry::instance()->service<TestObject11>()->holder = holder0; |
||||
|
ServiceRegistry::instance()->registerObject<TestObject12>(ServiceRegistry::DestroyOnAppDestroy); |
||||
|
QVERIFY(ServiceRegistry::instance()->service<TestObject12>()); |
||||
|
ServiceRegistry::instance()->service<TestObject12>()->holder = holder1; |
||||
|
ServiceRegistry::instance()->registerObject<TestObject13>(ServiceRegistry::DestroyOnRegistryDestroy); |
||||
|
QVERIFY(ServiceRegistry::instance()->service<TestObject13>()); |
||||
|
ServiceRegistry::instance()->service<TestObject13>()->holder = holder2; |
||||
|
ServiceRegistry::instance()->registerObject<TestObject14>(ServiceRegistry::DestroyNever); |
||||
|
QVERIFY(ServiceRegistry::instance()->service<TestObject14>()); |
||||
|
ServiceRegistry::instance()->service<TestObject14>()->holder = holder3; |
||||
|
} |
||||
|
|
||||
|
QVERIFY(weak0); |
||||
|
QVERIFY(weak1); |
||||
|
QVERIFY(weak2); |
||||
|
QVERIFY(weak3); |
||||
|
|
||||
|
bool called = false; |
||||
|
connect(qApp, &QCoreApplication::aboutToQuit, [&](){ //called after the method destructor
|
||||
|
QVERIFY(!weak0); |
||||
|
QVERIFY(weak1); |
||||
|
QVERIFY(weak2); |
||||
|
QVERIFY(weak3); |
||||
|
called = true; |
||||
|
}); |
||||
|
|
||||
|
// "run" the main eventloop to test the signal
|
||||
|
QTimer::singleShot(0, qApp, &QCoreApplication::quit); |
||||
|
QCoreApplication::exec(); |
||||
|
QVERIFY(called); |
||||
|
QVERIFY(!weak0); |
||||
|
QVERIFY(weak1); |
||||
|
QVERIFY(weak2); |
||||
|
QVERIFY(weak3); |
||||
|
} catch(QException &e) { |
||||
|
QFAIL(e.what()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// manual main for testing destruction
|
||||
|
int main(int argc, char *argv[]) |
||||
|
{ |
||||
|
int res = EXIT_FAILURE; |
||||
|
{ |
||||
|
QCoreApplication app(argc, argv); |
||||
|
app.setAttribute(Qt::AA_Use96Dpi, true); |
||||
|
ServiceRegistryTest tc; |
||||
|
QTEST_SET_MAIN_SOURCE_PATH |
||||
|
res = QTest::qExec(&tc, argc, argv); |
||||
|
Q_ASSERT(!ServiceRegistryTest::weak0); |
||||
|
Q_ASSERT(ServiceRegistryTest::weak1); |
||||
|
Q_ASSERT(ServiceRegistryTest::weak2); |
||||
|
Q_ASSERT(ServiceRegistryTest::weak3); |
||||
|
} |
||||
|
|
||||
|
Q_ASSERT(!ServiceRegistryTest::weak0); |
||||
|
Q_ASSERT(!ServiceRegistryTest::weak1); |
||||
|
Q_ASSERT(ServiceRegistryTest::weak2); |
||||
|
Q_ASSERT(ServiceRegistryTest::weak3); |
||||
|
|
||||
|
return res; |
||||
|
} |
||||
|
|
||||
|
#include "tst_serviceregistry.moc" |
@ -0,0 +1,3 @@ |
|||||
|
{ |
||||
|
"Keys" : [ "test1", "test2" ] |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
TEMPLATE = lib |
||||
|
CONFIG += plugin |
||||
|
|
||||
|
QT = core mvvmcore |
||||
|
|
||||
|
load(qt_build_paths) |
||||
|
|
||||
|
TARGET = serviceregistry_testplugin |
||||
|
DESTDIR = $$MODULE_BASE_OUTDIR/tests/plugins/serviceregistry |
||||
|
|
||||
|
HEADERS += \ |
||||
|
testplugin.h \ |
||||
|
../serviceregistry/plugintestinterface.h |
||||
|
|
||||
|
SOURCES += \ |
||||
|
testplugin.cpp |
||||
|
|
||||
|
DISTFILES += serviceregistrytestplugin.json |
@ -0,0 +1,10 @@ |
|||||
|
#include "testplugin.h" |
||||
|
|
||||
|
TestPlugin::TestPlugin(QObject *parent) : |
||||
|
QObject{parent} |
||||
|
{} |
||||
|
|
||||
|
int TestPlugin::magicNumber() const |
||||
|
{ |
||||
|
return 72; |
||||
|
} |
@ -0,0 +1,18 @@ |
|||||
|
#ifndef TESTPLUGIN_H |
||||
|
#define TESTPLUGIN_H |
||||
|
|
||||
|
#include "../serviceregistry/plugintestinterface.h" |
||||
|
|
||||
|
class TestPlugin : public QObject, public PluginTestInterface |
||||
|
{ |
||||
|
Q_OBJECT |
||||
|
Q_INTERFACES(PluginTestInterface) |
||||
|
Q_PLUGIN_METADATA(IID PluginTestInterfaceIId FILE "serviceregistrytestplugin.json") |
||||
|
|
||||
|
public: |
||||
|
TestPlugin(QObject *parent = nullptr); |
||||
|
|
||||
|
int magicNumber() const override; |
||||
|
}; |
||||
|
|
||||
|
#endif // TESTPLUGIN_H
|
Loading…
Reference in new issue