文章目录
- 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 _DEBUGusing MsgType = std::string;
#elseusing MsgType = const char*;
#endiffriend 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 _DEBUGusing MsgType = std::string;
#elseusing MsgType = const char*;
#endiffriend 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()
{
}