文章目录
-
-
- 1.全局消息通信
-
- MsgHandler.h
- 单元测试(QTest)
-
- MsgHandlerUnitTest.h
- MsgHandlerUnitTest.cpp
- 2.实例间通信
-
- InstMsgHandler.h
- 单元测试
-
- InstMsgHandlerUnitTest.h
- InstMsgHandlerUnitTest.cpp
1.全局消息通信
1. 适用于类与类单个对象实例之间的通信,多个对象需要酌情使用
2. 支持优先级触发
3. 支持附带参数
4. 支持异步执行
5. 使用方式可以查看下方单元测试代码
MsgHandler.h
#pragma once
#include <functional>
#include <unordered_map>
#include <map>
#include <string>
#include "any.h"
class MsgHandler {
#ifdef _DEBUG
using MsgType = std::string;
#else
using MsgType = const char*;
#endif
friend class MsgHandlerUnitTest;
public:
static MsgHandler* GetInstance() {
static MsgHandler i;
return &i;
}
void SetAsyncExecFunc(std::function<void(std::function<void()>)> func) { asyncExecFunc_ = func; }
void SetMainExecFunc(std::function<void(std::function<void()>)> func) { mainExecFunc_ = func; }
void TriggerMsg_(MsgType msg, std::any info = std::any{}) {
ExecMsgHandler(msg, defaultExecFunc_, info);
}
void AsyncExecMsg_(MsgType msg, std::any info = std::any{}) {
if(!asyncExecFunc_) throw std::runtime_error("dont set async exec func");
ExecMsgHandler(msg, asyncExecFunc_, info);
}
void MainExecMsg_(MsgType msg, std::any info = std::any{}) {
if (!mainExecFunc_) throw std::runtime_error("dont set main exec func");
ExecMsgHandler(msg, mainExecFunc_, info);
}
void RegisterMsgHandler_(MsgType msg, void* t, std::function<void(std::any)> func, int priority = 0) {
globalMsgHandler_[msg][priority].insert({ t, func });
}
void RegisterMsgHandler_(MsgType msg, void* t, std::function<void()> func, int priority = 0) {
globalMsgHandler_[msg][priority].insert({ t, [=](std::any) {func(); } });
}
void Deregister_(void* t) {
for (auto& msgHandler : globalMsgHandler_) {
PriorityMap& priorityMap = msgHandler.second;
for (auto& priorityEntry : priorityMap) {
HandlerMap& handlerMap = priorityEntry.second;
handlerMap.erase(t);
}
}
}
private:
void ExecMsgHandler(MsgType msg, std::function<void(std::function<void()>)> func, std::any info = std::any{}) {
auto it = globalMsgHandler_.find(msg);
if (it != globalMsgHandler_.end()) {
PriorityMap& priorityMap = it->second;
for (auto& priorityEntry : priorityMap) {
HandlerMap& handlerMap = priorityEntry.second;
for (auto& handlerEntry : handlerMap) {
std::function<void(std::any)>& handler = handlerEntry.second;
func([&handler, info] {handler(info); });
}
}
}
}
private:
MsgHandler() = default;
using HandlerMap = std::unordered_map<void*, std::function<void(std::any)>>;
using PriorityMap = std::map<int, HandlerMap, std::greater<int>>;
std::function<void(std::function<void()>)> defaultExecFunc_ = [](std::function<void()> func) { func(); };
std::function<void(std::function<void()>)> asyncExecFunc_;
std::function<void(std::function<void()>)> mainExecFunc_;
std::unordered_map<MsgType, PriorityMap> globalMsgHandler_;
};
#define RegisterMsgHandler(msg, ...) MsgHandler::GetInstance()->RegisterMsgHandler_(#msg, this, __VA_ARGS__)
#define TriggerMsg(msg, ...) MsgHandler::GetInstance()->TriggerMsg_(#msg, __VA_ARGS__)
#define AsyncExecMsg(msg, ...) MsgHandler::GetInstance()->AsyncExecMsg_(#msg, __VA_ARGS__)
#define MainExecMsg(msg, ...) MsgHandler::GetInstance()->MainExecMsg_(#msg, __VA_ARGS__)
#define Deregister() MsgHandler::GetInstance()->Deregister_(this)
单元测试(QTest)
MsgHandlerUnitTest.h
#include <QTest>
#include <vector>
class MsgHandlerUnitTest :public QObject {
Q_OBJECT
private slots:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
void RegisterTest();
void DeregisterTest();
void PriorityPreTest();
void PriorityTest();
void TriggerNoParamTest();
void TriggerHasParamTest();
void AsyncTriggerTest();
void MainTriggerTest();
void MemoryLeakTest();
private:
bool VarifyResult();
private:
std::vector<bool> m_results;
};
MsgHandlerUnitTest.cpp
#include "MsgHandlerUnitTest.h"
#include "MsgHandler.h"
#include <QTimer>
class RunnableTask : public QRunnable {
public:
RunnableTask(std::function<void()> func) : func_(func) {
setAutoDelete(true);
}
void run() { func_(); }
private:
std::function<void()> func_;
};
class AsyncThreadPool {
public:
void AddTask(std::function<void()> func) {
QThreadPool::globalInstance()->start(new RunnableTask(func));
}
public:
static AsyncThreadPool* GetInstance() {
static AsyncThreadPool i;
return &i;
}
private:
AsyncThreadPool() = default;
};
#define GAsyncThreadPool AsyncThreadPool::GetInstance()
int GetCurMemoryKB()
{
SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
PROCESS_MEMORY_COUNTERS pmc;
GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
auto curMemoryKB = pmc.WorkingSetSize / 1024;
return curMemoryKB;
}
enum Msg {
A,
B,
C,
};
void MsgHandlerUnitTest::RegisterTest()
{
struct ClassA {
ClassA() {
RegisterMsgHandler(Msg::A, [this] {});
RegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
Deregister();
}
};
struct ClassB {
ClassB() {
RegisterMsgHandler(Msg::A, [this] {});
RegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassB() {
Deregister();
}
};
ClassA a1;
const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 1);
ClassA a2;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 2);
ClassB b1;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 3);
m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 3);
QVERIFY(VarifyResult());
}
void MsgHandlerUnitTest::DeregisterTest() {
struct ClassA {
ClassA() {
RegisterMsgHandler(Msg::A, [this] {});
RegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
Deregister();
}
};
const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;
{
ClassA a1;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 1);
}
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 0);
m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 0);
QVERIFY(VarifyResult());
}
void MsgHandlerUnitTest::PriorityPreTest() {
struct ClassA {
ClassA() {
RegisterMsgHandler(Msg::A, [this] {});
RegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
Deregister();
}
};
struct ClassB {
ClassB() {
RegisterMsgHandler(Msg::A, [this] {}, 1);
RegisterMsgHandler(Msg::B, [this](const std::any& data) {}, 1);
}
~ClassB() {
Deregister();
}
};
const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;
ClassA a1;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 1);
ClassA a2;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 2);
ClassB b;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").at(1).size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").at(1).size() == 1);
QVERIFY(VarifyResult());
}
std::vector<int> priorityTestvec;
void MsgHandlerUnitTest::PriorityTest()
{
struct ClassA {
ClassA() {
RegisterMsgHandler(Msg::A, [this] {
priorityTestvec.push_back(a);
});
RegisterMsgHandler(Msg::B, [this] {
priorityTestvec.push_back(a);
}, 1);
}
~ClassA() {
Deregister();
}
int a = 5;
};
struct ClassB {
ClassB() {
RegisterMsgHandler(Msg::A, [this] {
priorityTestvec.push_back(b);
}, 1);
RegisterMsgHandler(Msg::B, [this] {
priorityTestvec.push_back(b);
});
}
~ClassB() {
Deregister();
}
int b = 10;
};
ClassA a;
ClassB b;
priorityTestvec.clear();
TriggerMsg(Msg::A);
m_results.push_back(priorityTestvec.size() == 2);
m_results.push_back(priorityTestvec[0] == 10 && priorityTestvec[1] == 5);
priorityTestvec.clear();
TriggerMsg(Msg::B);
m_results.push_back(priorityTestvec.size() == 2);
m_results.push_back(priorityTestvec[0] == 5 && priorityTestvec[1] == 10);
QVERIFY(VarifyResult());
}
void MsgHandlerUnitTest::TriggerNoParamTest()
{
struct ClassA {
ClassA() {
RegisterMsgHandler(Msg::A, [this] {
a = A;
});
RegisterMsgHandler(Msg::B, [this] {
a = B;
});
}
~ClassA() {
Deregister();
}
int a = 0;
};
struct ClassB {
ClassB() {
RegisterMsgHandler(Msg::A, [this] {
b = A;
});
RegisterMsgHandler(Msg::B, [this] {
b = B;
});
}
~ClassB() {
Deregister();
}
int b = 0;
};
const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;
ClassA a1;
ClassB b1;
m_results.push_back(a1.a == 0);
m_results.push_back(b1.b == 0);
TriggerMsg(Msg::A);
m_results.push_back(a1.a == A);
m_results.push_back(b1.b == A);
TriggerMsg(Msg::B);
m_results.push_back(a1.a == B);
m_results.push_back(b1.b == B);
QVERIFY(VarifyResult());
}
void MsgHandlerUnitTest::TriggerHasParamTest()
{
struct ClassA {
ClassA() {
RegisterMsgHandler(Msg::C, [this](const std::any& data) {
a = std::any_cast<int>(data);
});
}
~ClassA() {
Deregister();
}
int a = 0;
};
struct ClassB {
ClassB() {
RegisterMsgHandler(Msg::C, [this](const std::any& data) {
b = std::any_cast<int>(data);
});
}
~ClassB() {
Deregister();
}
int b = 0;
};
const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;
ClassA a1;
ClassB b1;
m_results.push_back(a1.a == 0);
m_results.push_back(b1.b == 0);
TriggerMsg(Msg::C, 5);
m_results.push_back(a1.a == 5);
m_results.push_back(b1.b == 5);
TriggerMsg(Msg::C, 999);
m_results.push_back(a1.a == 999);
m_results.push_back(b1.b == 999);
QVERIFY(VarifyResult());
}
std::vector<std::thread::id> AsyncTriggerTestVec;
void MsgHandlerUnitTest::AsyncTriggerTest()
{
AsyncTriggerTestVec.push_back(std::this_thread::get_id());
struct ClassA {
ClassA() {
RegisterMsgHandler(Msg::A, [this] {
AsyncTriggerTestVec.push_back(std::this_thread::get_id());
});
}
~ClassA() {
Deregister();
}
};
ClassA a;
AsyncExecMsg(Msg::A);
while (AsyncTriggerTestVec.size() != 2) {
QCoreApplication::processEvents();
}
m_results.push_back(AsyncTriggerTestVec[0] != AsyncTriggerTestVec[1]);
QVERIFY(VarifyResult());
}
std::vector<std::thread::id> MainTriggerTestVec;
void MsgHandlerUnitTest::MainTriggerTest()
{
MainTriggerTestVec.clear();
MainTriggerTestVec.push_back(std::this_thread::get_id());
struct ClassA {
ClassA() {
RegisterMsgHandler(Msg::A, [this] {
MainTriggerTestVec.push_back(std::this_thread::get_id());
MainExecMsg(Msg::B);
});
RegisterMsgHandler(Msg::B, [this] {
MainTriggerTestVec.push_back(std::this_thread::get_id());
});
}
~ClassA() {
Deregister();
}
};
ClassA a;
AsyncExecMsg(Msg::A);
while (MainTriggerTestVec.size() != 3) {
QCoreApplication::processEvents();
}
m_results.push_back(MainTriggerTestVec[0] != MainTriggerTestVec[1]
&& MainTriggerTestVec[1] != MainTriggerTestVec[2]
&& MainTriggerTestVec[0] == MainTriggerTestVec[2]);
QVERIFY(VarifyResult());
}
void MsgHandlerUnitTest::MemoryLeakTest()
{
struct ClassA {
ClassA() {
RegisterMsgHandler(Msg::A, [this] {
a = A;
});
RegisterMsgHandler(Msg::B, [this] {
a = B;
});
RegisterMsgHandler(Msg::C, [this](const std::any& data) {
a = std::any_cast<int>(data);
});
}
~ClassA() {
Deregister();
}
int a = 0;
};
const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;
auto beginMemory = GetCurMemoryKB();
{
std::vector<ClassA*> vec;
for (int i = 0; i < 100000; ++i) {
vec.push_back(new ClassA);
}
m_results.push_back(globalMsgHandler.size() == 3);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::C").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 100000);
m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 100000);
m_results.push_back(globalMsgHandler.at("Msg::C").at(0).size() == 100000);
for (auto& v : vec) {
delete v;
}
vec.clear();
m_results.push_back(globalMsgHandler.size() == 3);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::C").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 0);
m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 0);
m_results.push_back(globalMsgHandler.at("Msg::C").at(0).size() == 0);
}
auto endMemory = GetCurMemoryKB();
QVERIFY(endMemory - beginMemory < 30);
}
bool MsgHandlerUnitTest::VarifyResult()
{
bool result = true;
for (auto& rlt : m_results) {
if (!rlt) {
result = false;
break;
}
}
return result;
}
void MsgHandlerUnitTest::initTestCase()
{
MsgHandler::GetInstance()->SetAsyncExecFunc([](std::function<void()> func) { GAsyncThreadPool->AddTask(func); });
MsgHandler::GetInstance()->SetMainExecFunc([](std::function<void()> func) { QTimer::singleShot(0, qApp, func); });
}
void MsgHandlerUnitTest::cleanupTestCase()
{
}
void MsgHandlerUnitTest::init()
{
m_results.clear();
MsgHandler::GetInstance()->globalMsgHandler_.clear();
}
void MsgHandlerUnitTest::cleanup()
{
}
2.实例间通信
1. 适用于类与类相互关联的对象之间的通信
2. 不支持优先级触发
3. 支持附带参数
4. 不支持异步执行
5. 使用方式可以查看下方单元测试代码
InstMsgHandler.h
#pragma once
#include <unordered_map>
#include <functional>
#include <unordered_set>
#include "any.h"
class InstMsgHandler {
#ifdef _DEBUG
using MsgType = std::string;
#else
using MsgType = const char*;
#endif
friend class InstMsgHandlerUnitTest;
public:
static InstMsgHandler* GetInstance() {
static InstMsgHandler i;
return &i;
}
void XTriggerMsg_(MsgType msg, void* trigger, std::any info = std::any{}) {
auto findHandler = globalMsgHandler_.find(msg);
if (findHandler != globalMsgHandler_.end()) {
auto& handlers = findHandler->second;
auto it = communicators_.find(trigger);
if (it != communicators_.end()) {
for (const auto& communicator : it->second) {
auto handler = handlers.find(communicator);
if (handler != handlers.end()) {
handler->second(info);
}
}
}
}
}
void XRegisterMsgHandler_(MsgType msg, void* t, std::function<void(std::any)> func) {
globalMsgHandler_[msg].insert({ t, func });
}
void XRegisterMsgHandler_(MsgType msg, void* t, std::function<void()> func) {
globalMsgHandler_[msg].insert({ t, [=](std::any) {func(); } });
}
void XConnect_(void* c1, void* c2) {
if (c1 == c2) {
communicators_[c1].insert(c2);
return;
}
communicators_[c1].insert(c2);
communicators_[c2].insert(c1);
}
void XDisconnect_(void* c1, void* c2) {
if (c1 == c2) {
communicators_[c1].erase(c2);
return;
}
communicators_[c1].erase(c2);
communicators_[c2].erase(c1);
}
void XDeregister_(void* t) {
XDisconnect_(t);
DeregisterMsgHandler(t);
}
private:
void XDisconnect_(void* t) {
auto it = communicators_.find(t);
if (it != communicators_.end()) {
auto communicators = it->second;
for (auto communicator : communicators) {
communicators_[communicator].erase(t);
}
}
communicators_.erase(t);
}
void DeregisterMsgHandler(void* t) {
for (auto& msgHandler : globalMsgHandler_) {
HandlerMap& handlerMap = msgHandler.second;
handlerMap.erase(t);
}
}
private:
InstMsgHandler() = default;
using HandlerMap = std::unordered_map<void*, std::function<void(std::any)>>;
std::unordered_map<void*, std::unordered_set<void*>> communicators_;
std::unordered_map<MsgType, HandlerMap> globalMsgHandler_;
};
#define EXPAND(...) __VA_ARGS__
#define COUNT_ARGS_IMPL(_1, _2, _3, N, ...) N
#define COUNT_ARGS(...) EXPAND(COUNT_ARGS_IMPL(__VA_ARGS__, 3, 2, 1, 0))
#define XCONNECT_IMPL_1(a) InstMsgHandler::GetInstance()->XConnect_(this, a)
#define XCONNECT_IMPL_2(a, b) InstMsgHandler::GetInstance()->XConnect_(a, b)
#define XCONNECT_IMPL(n) XCONNECT_IMPL_##n
#define XCONNECT_DISPATCH(n, ...) EXPAND(XCONNECT_IMPL(n)(__VA_ARGS__))
#define XConnect(...) XCONNECT_DISPATCH(EXPAND(COUNT_ARGS(__VA_ARGS__)), __VA_ARGS__)
#define XDISCONNECT_IMPL_1(a) InstMsgHandler::GetInstance()->XDisconnect_(this, a)
#define XDISCONNECT_IMPL_2(a, b) InstMsgHandler::GetInstance()->XDisconnect_(a, b)
#define XDISCONNECT_IMPL(n) XDISCONNECT_IMPL_##n
#define XDISCONNECT_DISPATCH(n, ...) EXPAND(XDISCONNECT_IMPL(n)(__VA_ARGS__))
#define XDisconnect(...) XDISCONNECT_DISPATCH(EXPAND(COUNT_ARGS(__VA_ARGS__)), __VA_ARGS__)
#define XRegisterMsgHandler(msg, ...) InstMsgHandler::GetInstance()->XRegisterMsgHandler_(#msg, this, __VA_ARGS__)
#define XTriggerMsg(msg, ...) InstMsgHandler::GetInstance()->XTriggerMsg_(#msg, this, __VA_ARGS__)
#define XDeregister() InstMsgHandler::GetInstance()->XDeregister_(this)
单元测试
InstMsgHandlerUnitTest.h
#include <QTest>
#include <vector>
class InstMsgHandlerUnitTest :public QObject {
Q_OBJECT
private slots:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
void RegisterTest();
void DeregisterTest();
void XConnectABTest();
void XDisconnectABTest();
void ABTriggerNoParamTest();
void ABTriggerHasParamTest();
void XConnectBaseTest();
void BaseTriggerNoParamTest();
void BaseTriggerHasParamTest();
void MemoryLeakTest();
void BaseMemoryLeakTest();
private:
bool VarifyResult();
private:
std::vector<bool> m_results;
};
InstMsgHandlerUnitTest.cpp
#include "InstMsgHandlerUnitTest.h"
#include "InstMsgHandler.h"
int GetCurMemoryKB()
{
SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);
PROCESS_MEMORY_COUNTERS pmc;
GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));
auto curMemoryKB = pmc.WorkingSetSize / 1024;
return curMemoryKB;
}
enum Msg {
A,
B,
C,
};
void InstMsgHandlerUnitTest::RegisterTest()
{
struct ClassA {
ClassA() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
XDeregister();
}
};
struct ClassB {
ClassB() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassB() {
XDeregister();
}
};
ClassA a;
const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
ClassB b;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);
QVERIFY(VarifyResult());
}
void InstMsgHandlerUnitTest::DeregisterTest()
{
struct ClassA {
ClassA() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
XDeregister();
}
};
struct ClassB {
ClassB() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassB() {
XDeregister();
}
};
const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;
const auto& communicators = InstMsgHandler::GetInstance()->communicators_;
{
ClassA a;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(communicators.size() == 0);
{
ClassB b;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);
XConnect(&a, &b);
m_results.push_back(communicators.size() == 2);
m_results.push_back(communicators.at(&a).size() == 1);
m_results.push_back(communicators.at(&b).size() == 1);
}
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(communicators.size() == 1);
m_results.push_back(communicators.at(&a).size() == 0);
}
m_results.push_back(communicators.size() == 0);
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 0);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 0);
QVERIFY(VarifyResult());
}
void InstMsgHandlerUnitTest::XConnectABTest()
{
struct ClassA {
ClassA() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
XDeregister();
}
};
struct ClassB {
ClassB() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassB() {
XDeregister();
}
};
ClassA a;
ClassB b;
XConnect(&a, &b);
const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;
const auto& communicators = InstMsgHandler::GetInstance()->communicators_;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);
m_results.push_back(communicators.size() == 2);
m_results.push_back(communicators.at(&a).size() == 1);
m_results.push_back(communicators.at(&b).size() == 1);
QVERIFY(VarifyResult());
}
void InstMsgHandlerUnitTest::XDisconnectABTest()
{
struct ClassA {
ClassA() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
XDeregister();
}
};
struct ClassB {
ClassB() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassB() {
XDeregister();
}
};
ClassA a;
ClassB b;
XConnect(&a, &b);
const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;
const auto& communicators = InstMsgHandler::GetInstance()->communicators_;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);
m_results.push_back(communicators.size() == 2);
m_results.push_back(communicators.at(&a).size() == 1);
m_results.push_back(communicators.at(&b).size() == 1);
XDisconnect(&a, &b);
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);
m_results.push_back(communicators.size() == 2);
m_results.push_back(communicators.at(&a).size() == 0);
m_results.push_back(communicators.at(&b).size() == 0);
QVERIFY(VarifyResult());
}
int TriggerNoParamTestTempVar = 0;
void InstMsgHandlerUnitTest::ABTriggerNoParamTest()
{
TriggerNoParamTestTempVar = 0;
struct ClassA {
ClassA() {
XRegisterMsgHandler(Msg::A, [this] {
TriggerNoParamTestTempVar += 1;
});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
XDeregister();
}
void Call() {
XTriggerMsg(Msg::A);
}
};
struct ClassB {
ClassB() {
XRegisterMsgHandler(Msg::A, [this] {
TriggerNoParamTestTempVar += 1;
});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassB() {
XDeregister();
}
void Call() {
XTriggerMsg(Msg::A);
}
};
ClassA a;
ClassB b;
XConnect(&a, &b);
const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;
const auto& communicators = InstMsgHandler::GetInstance()->communicators_;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);
m_results.push_back(communicators.size() == 2);
m_results.push_back(communicators.at(&a).size() == 1);
m_results.push_back(communicators.at(&b).size() == 1);
a.Call();
m_results.push_back(TriggerNoParamTestTempVar == 1);
b.Call();
m_results.push_back(TriggerNoParamTestTempVar == 2);
XDisconnect(&a, &b);
a.Call();
m_results.push_back(TriggerNoParamTestTempVar == 2);
b.Call();
m_results.push_back(TriggerNoParamTestTempVar == 2);
QVERIFY(VarifyResult());
}
int TriggerHasParamTestTempVar = 0;
void InstMsgHandlerUnitTest::ABTriggerHasParamTest()
{
TriggerHasParamTestTempVar = 0;
struct ClassA {
ClassA() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {
TriggerHasParamTestTempVar = std::any_cast<int>(data);
});
}
~ClassA() {
XDeregister();
}
void Call() {
XTriggerMsg(Msg::B, 100);
}
};
struct ClassB {
ClassB() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {
TriggerHasParamTestTempVar = std::any_cast<int>(data);
});
}
~ClassB() {
XDeregister();
}
void Call() {
XTriggerMsg(Msg::B, -100);
}
};
ClassA a;
ClassB b;
XConnect(&a, &b);
const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;
const auto& communicators = InstMsgHandler::GetInstance()->communicators_;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);
m_results.push_back(communicators.size() == 2);
m_results.push_back(communicators.at(&a).size() == 1);
m_results.push_back(communicators.at(&b).size() == 1);
a.Call();
m_results.push_back(TriggerHasParamTestTempVar == 100);
b.Call();
m_results.push_back(TriggerHasParamTestTempVar == -100);
QVERIFY(VarifyResult());
}
void InstMsgHandlerUnitTest::XConnectBaseTest()
{
struct ClassA {
ClassA() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
XDeregister();
}
};
struct ClassB : ClassA {
ClassB() {
XConnect(this);
}
~ClassB() {
XDeregister();
}
};
ClassB b;
const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;
const auto& communicators = InstMsgHandler::GetInstance()->communicators_;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(communicators.size() == 1);
m_results.push_back(communicators.at(&b).size() == 1);
}
int BaseTriggerNoParamTestTempVar = 0;
void InstMsgHandlerUnitTest::BaseTriggerNoParamTest()
{
BaseTriggerNoParamTestTempVar = 0;
struct ClassA {
ClassA() {
XRegisterMsgHandler(Msg::A, [this] {
BaseTriggerNoParamTestTempVar += 1;
});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
XDeregister();
}
void CallBase() {
XTriggerMsg(Msg::A);
}
};
struct ClassB : ClassA {
ClassB() {
XConnect(this);
}
~ClassB() {
XDeregister();
}
void CallDriver() {
XTriggerMsg(Msg::A);
}
};
ClassB b;
const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;
const auto& communicators = InstMsgHandler::GetInstance()->communicators_;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(communicators.size() == 1);
m_results.push_back(communicators.at(&b).size() == 1);
b.CallBase();
m_results.push_back(BaseTriggerNoParamTestTempVar == 1);
b.CallDriver();
m_results.push_back(BaseTriggerNoParamTestTempVar == 2);
QVERIFY(VarifyResult());
}
int BaseTriggerHasParamTestTempVar = 0;
void InstMsgHandlerUnitTest::BaseTriggerHasParamTest()
{
BaseTriggerHasParamTestTempVar = 0;
struct ClassA {
ClassA() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {
BaseTriggerHasParamTestTempVar = std::any_cast<int>(data);
});
}
~ClassA() {
XDeregister();
}
void CallBase() {
XTriggerMsg(Msg::B, 100);
}
};
struct ClassB : ClassA {
ClassB() {
XConnect(this);
}
~ClassB() {
XDeregister();
}
void CallDriver() {
XTriggerMsg(Msg::B, -100);
}
};
ClassB b;
const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;
const auto& communicators = InstMsgHandler::GetInstance()->communicators_;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);
m_results.push_back(communicators.size() == 1);
m_results.push_back(communicators.at(&b).size() == 1);
b.CallBase();
m_results.push_back(BaseTriggerHasParamTestTempVar == 100);
b.CallDriver();
m_results.push_back(BaseTriggerHasParamTestTempVar == -100);
QVERIFY(VarifyResult());
}
void InstMsgHandlerUnitTest::MemoryLeakTest()
{
struct ClassA {
ClassA() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
XDeregister();
}
int a = 0;
};
struct ClassB {
ClassB() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassB() {
XDeregister();
}
int b = 0;
};
auto beginMemory = GetCurMemoryKB();
{
std::vector<ClassA*> veca;
std::vector<ClassB*> vecb;
for (int i = 0; i < 10000; ++i) {
ClassA* a = new ClassA;
ClassB* b = new ClassB;
XConnect(a, b);
veca.push_back(a);
vecb.push_back(b);
}
const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;
const auto& communicators = InstMsgHandler::GetInstance()->communicators_;
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 20000);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 20000);
m_results.push_back(communicators.size() == 20000);
for (auto& communicator : communicators) {
QVERIFY(communicator.second.size() == 1);
}
for (auto& v : veca) {
delete v;
}
for (auto& v : vecb) {
delete v;
}
veca.clear();
vecb.clear();
m_results.push_back(globalMsgHandler.size() == 2);
m_results.push_back(globalMsgHandler.at("Msg::A").size() == 0);
m_results.push_back(globalMsgHandler.at("Msg::B").size() == 0);
m_results.push_back(communicators.size() == 0);
}
auto endMemory = GetCurMemoryKB();
QVERIFY(endMemory - beginMemory < 30);
}
void InstMsgHandlerUnitTest::BaseMemoryLeakTest()
{
struct ClassA {
ClassA() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
}
~ClassA() {
XDeregister();
}
int a = 0;
};
struct ClassB : ClassA {
ClassB() {
XRegisterMsgHandler(Msg::A, [this] {});
XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});
XConnect(this);
}
~ClassB() {
XDeregister();
}
int b = 0;
};
auto beginMemory = GetCurMemoryKB();
{
std::vector<ClassB*> vecb;
for (int i = 0; i < 10000; ++i) {
vecb.push_back(new ClassB);
}
for (auto& v : vecb) {
delete v;
}
vecb.clear();
}
auto endMemory = GetCurMemoryKB();
QVERIFY(endMemory - beginMemory < 30);
}
bool InstMsgHandlerUnitTest::VarifyResult()
{
bool result = true;
for (auto& rlt : m_results) {
if (!rlt) {
result = false;
break;
}
}
return result;
}
void InstMsgHandlerUnitTest::initTestCase()
{
}
void InstMsgHandlerUnitTest::cleanupTestCase()
{
}
void InstMsgHandlerUnitTest::init()
{
m_results.clear();
InstMsgHandler::GetInstance()->globalMsgHandler_.clear();
InstMsgHandler::GetInstance()->communicators_.clear();
}
void InstMsgHandlerUnitTest::cleanup()
{
}