Skip to content

Commit ac0ed1f

Browse files
committed
#5422: Add unit tests covering the MessageBus behaviour
1 parent bd5d60b commit ac0ed1f

File tree

4 files changed

+175
-0
lines changed

4 files changed

+175
-0
lines changed

test/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ drtest_SOURCES = math/Matrix4.cpp \
3434
FacePlane.cpp \
3535
Materials.cpp \
3636
MapExport.cpp \
37+
MessageBus.cpp \
3738
Models.cpp \
3839
ModelExport.cpp \
3940
ModelScale.cpp \

test/MessageBus.cpp

Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
#include "RadiantTest.h"
2+
3+
#include <future>
4+
#include "imessagebus.h"
5+
6+
namespace test
7+
{
8+
9+
using MessageBusTest = RadiantTest;
10+
11+
class CustomMessage1 :
12+
public radiant::IMessage
13+
{
14+
public:
15+
static const std::size_t Id = radiant::IMessage::Type::UserDefinedMessagesGoHigherThanThis + 1000;
16+
17+
std::size_t getId() const override
18+
{
19+
return Id;
20+
}
21+
};
22+
23+
class CustomMessage2 :
24+
public radiant::IMessage
25+
{
26+
public:
27+
static const std::size_t Id = radiant::IMessage::Type::UserDefinedMessagesGoHigherThanThis + 1001;
28+
29+
std::size_t getId() const override
30+
{
31+
return Id;
32+
}
33+
};
34+
35+
TEST_F(MessageBusTest, Registration)
36+
{
37+
auto counter1 = 0;
38+
auto& messageBus = GlobalRadiantCore().getMessageBus();
39+
40+
auto listenerId1 = messageBus.addListener(CustomMessage1::Id, [&](radiant::IMessage&) { ++counter1; });
41+
42+
CustomMessage1 msg1;
43+
messageBus.sendMessage(msg1);
44+
45+
// Counter should have been increased
46+
EXPECT_EQ(counter1, 1);
47+
48+
messageBus.removeListener(listenerId1);
49+
50+
// Send another message, counter should not increase
51+
messageBus.sendMessage(msg1);
52+
53+
EXPECT_EQ(counter1, 1);
54+
}
55+
56+
TEST_F(MessageBusTest, ChannelHandling)
57+
{
58+
auto counter1 = 0;
59+
auto counter2 = 0;
60+
auto& messageBus = GlobalRadiantCore().getMessageBus();
61+
62+
auto listenerId1 = messageBus.addListener(CustomMessage1::Id, [&](radiant::IMessage&) { ++counter1; });
63+
auto listenerId2 = messageBus.addListener(CustomMessage2::Id, [&](radiant::IMessage&) { ++counter2; });
64+
65+
EXPECT_NE(listenerId1, listenerId2);
66+
67+
CustomMessage1 msg1;
68+
messageBus.sendMessage(msg1);
69+
70+
// Only one counter should have been increased
71+
EXPECT_EQ(counter1, 1);
72+
EXPECT_EQ(counter2, 0);
73+
}
74+
75+
TEST_F(MessageBusTest, MultipleListenersOnChannel)
76+
{
77+
auto counter1 = 0;
78+
auto& messageBus = GlobalRadiantCore().getMessageBus();
79+
80+
auto listenerId1 = messageBus.addListener(CustomMessage1::Id, [&](radiant::IMessage&) { ++counter1; });
81+
auto listenerId2 = messageBus.addListener(CustomMessage1::Id, [&](radiant::IMessage&) { ++counter1; });
82+
83+
CustomMessage1 msg1;
84+
messageBus.sendMessage(msg1);
85+
86+
// Counter should have been increased twice
87+
EXPECT_EQ(counter1, 2);
88+
89+
messageBus.removeListener(listenerId1);
90+
91+
// Send another message, counter should increase only once now
92+
messageBus.sendMessage(msg1);
93+
94+
EXPECT_EQ(counter1, 3);
95+
}
96+
97+
TEST_F(MessageBusTest, DeregistrationDuringCallback)
98+
{
99+
auto counter1 = 0;
100+
auto& messageBus = GlobalRadiantCore().getMessageBus();
101+
102+
// Two listeners, unsubscribing during callback
103+
std::size_t listenerId1 = 0;
104+
std::size_t listenerId2 = 0;
105+
106+
listenerId1 = messageBus.addListener(CustomMessage1::Id, [&](radiant::IMessage&)
107+
{
108+
++counter1;
109+
messageBus.removeListener(listenerId1);
110+
});
111+
112+
listenerId2 = messageBus.addListener(CustomMessage1::Id, [&](radiant::IMessage&)
113+
{
114+
++counter1;
115+
messageBus.removeListener(listenerId2);
116+
});
117+
118+
CustomMessage1 msg1;
119+
messageBus.sendMessage(msg1);
120+
121+
// Counter should have been increased twice
122+
EXPECT_EQ(counter1, 2);
123+
124+
// Send another message, counter should not increase anymore
125+
messageBus.sendMessage(msg1);
126+
127+
EXPECT_EQ(counter1, 2);
128+
}
129+
130+
TEST_F(MessageBusTest, MultipleThreadsCanSendMessages)
131+
{
132+
std::size_t counter = 0;
133+
auto& messageBus = GlobalRadiantCore().getMessageBus();
134+
135+
// Add a handler that launches another thread which in turn is sending messages
136+
auto listenerId1 = messageBus.addListener(CustomMessage1::Id, [&](radiant::IMessage&)
137+
{
138+
++counter;
139+
140+
// Launch a separate thread which is sending messages
141+
std::thread innerThread([&]()
142+
{
143+
CustomMessage2 msg2;
144+
messageBus.sendMessage(msg2);
145+
});
146+
147+
// If the sendMessage(CustomMessage2) deadlocks, this will never return
148+
innerThread.join();
149+
150+
++counter; // finish => counter == 2
151+
});
152+
153+
auto task = std::async(std::launch::async, [&]()
154+
{
155+
CustomMessage1 msg1;
156+
messageBus.sendMessage(msg1);
157+
});
158+
159+
auto result = task.wait_for(std::chrono::seconds(2));
160+
161+
EXPECT_EQ(counter, 2);
162+
EXPECT_EQ(result, std::future_status::ready) << "Inner thread doesn't respond, possibly dead-locked";
163+
164+
if (result == std::future_status::timeout)
165+
{
166+
// In case of a deadlock the destructor of the above task
167+
// would wait forever, abort the whole test application
168+
std::terminate();
169+
}
170+
}
171+
172+
}

tools/msvc/Tests/Tests.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
<ClCompile Include="..\..\..\test\math\Plane3.cpp" />
7777
<ClCompile Include="..\..\..\test\math\Quaternion.cpp" />
7878
<ClCompile Include="..\..\..\test\math\Vector3.cpp" />
79+
<ClCompile Include="..\..\..\test\MessageBus.cpp" />
7980
<ClCompile Include="..\..\..\test\ModelExport.cpp" />
8081
<ClCompile Include="..\..\..\test\Models.cpp" />
8182
<ClCompile Include="..\..\..\test\ModelScale.cpp" />

tools/msvc/Tests/Tests.vcxproj.filters

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<ClCompile Include="..\..\..\test\Models.cpp" />
2727
<ClCompile Include="..\..\..\test\Face.cpp" />
2828
<ClCompile Include="..\..\..\test\Selection.cpp" />
29+
<ClCompile Include="..\..\..\test\MessageBus.cpp" />
2930
</ItemGroup>
3031
<ItemGroup>
3132
<ClInclude Include="..\..\..\test\HeadlessOpenGLContext.h" />

0 commit comments

Comments
 (0)