1 /*
2 * Copyright 2012 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "rtc_base/third_party/sigslot/sigslot.h"
12
13 #include "test/gtest.h"
14
15 // This function, when passed a has_slots or signalx, will break the build if
16 // its threading requirement is not single threaded
TemplateIsST(const sigslot::single_threaded * p)17 static bool TemplateIsST(const sigslot::single_threaded* p) {
18 return true;
19 }
20 // This function, when passed a has_slots or signalx, will break the build if
21 // its threading requirement is not multi threaded
TemplateIsMT(const sigslot::multi_threaded_local * p)22 static bool TemplateIsMT(const sigslot::multi_threaded_local* p) {
23 return true;
24 }
25
26 class SigslotDefault : public ::testing::Test, public sigslot::has_slots<> {
27 protected:
28 sigslot::signal0<> signal_;
29 };
30
31 template <class slot_policy = sigslot::single_threaded,
32 class signal_policy = sigslot::single_threaded>
33 class SigslotReceiver : public sigslot::has_slots<slot_policy> {
34 public:
SigslotReceiver()35 SigslotReceiver() : signal_(nullptr), signal_count_(0) {}
~SigslotReceiver()36 ~SigslotReceiver() {}
37
38 // Provide copy constructor so that tests can exercise the has_slots copy
39 // constructor.
40 SigslotReceiver(const SigslotReceiver&) = default;
41
Connect(sigslot::signal0<signal_policy> * signal)42 void Connect(sigslot::signal0<signal_policy>* signal) {
43 if (!signal)
44 return;
45 Disconnect();
46 signal_ = signal;
47 signal->connect(this,
48 &SigslotReceiver<slot_policy, signal_policy>::OnSignal);
49 }
Disconnect()50 void Disconnect() {
51 if (!signal_)
52 return;
53 signal_->disconnect(this);
54 signal_ = nullptr;
55 }
OnSignal()56 void OnSignal() { ++signal_count_; }
signal_count()57 int signal_count() { return signal_count_; }
58
59 private:
60 sigslot::signal0<signal_policy>* signal_;
61 int signal_count_;
62 };
63
64 template <class slot_policy = sigslot::single_threaded,
65 class mt_signal_policy = sigslot::multi_threaded_local>
66 class SigslotSlotTest : public ::testing::Test {
67 protected:
SigslotSlotTest()68 SigslotSlotTest() {
69 mt_signal_policy mt_policy;
70 TemplateIsMT(&mt_policy);
71 }
72
SetUp()73 virtual void SetUp() { Connect(); }
TearDown()74 virtual void TearDown() { Disconnect(); }
75
Disconnect()76 void Disconnect() {
77 st_receiver_.Disconnect();
78 mt_receiver_.Disconnect();
79 }
80
Connect()81 void Connect() {
82 st_receiver_.Connect(&SignalSTLoopback);
83 mt_receiver_.Connect(&SignalMTLoopback);
84 }
85
st_loop_back_count()86 int st_loop_back_count() { return st_receiver_.signal_count(); }
mt_loop_back_count()87 int mt_loop_back_count() { return mt_receiver_.signal_count(); }
88
89 sigslot::signal0<> SignalSTLoopback;
90 SigslotReceiver<slot_policy, sigslot::single_threaded> st_receiver_;
91 sigslot::signal0<mt_signal_policy> SignalMTLoopback;
92 SigslotReceiver<slot_policy, mt_signal_policy> mt_receiver_;
93 };
94
95 typedef SigslotSlotTest<> SigslotSTSlotTest;
96 typedef SigslotSlotTest<sigslot::multi_threaded_local,
97 sigslot::multi_threaded_local>
98 SigslotMTSlotTest;
99
100 class multi_threaded_local_fake : public sigslot::multi_threaded_local {
101 public:
multi_threaded_local_fake()102 multi_threaded_local_fake() : lock_count_(0), unlock_count_(0) {}
103
lock()104 void lock() { ++lock_count_; }
unlock()105 void unlock() { ++unlock_count_; }
106
lock_count()107 int lock_count() { return lock_count_; }
108
InCriticalSection()109 bool InCriticalSection() { return lock_count_ != unlock_count_; }
110
111 protected:
112 int lock_count_;
113 int unlock_count_;
114 };
115
116 typedef SigslotSlotTest<multi_threaded_local_fake, multi_threaded_local_fake>
117 SigslotMTLockBase;
118
119 class SigslotMTLockTest : public SigslotMTLockBase {
120 protected:
SigslotMTLockTest()121 SigslotMTLockTest() {}
122
SetUp()123 void SetUp() override {
124 EXPECT_EQ(0, SlotLockCount());
125 SigslotMTLockBase::SetUp();
126 // Connects to two signals (ST and MT). However,
127 // SlotLockCount() only gets the count for the
128 // MT signal (there are two separate SigslotReceiver which
129 // keep track of their own count).
130 EXPECT_EQ(1, SlotLockCount());
131 }
TearDown()132 void TearDown() override {
133 const int previous_lock_count = SlotLockCount();
134 SigslotMTLockBase::TearDown();
135 // Disconnects from two signals. Note analogous to SetUp().
136 EXPECT_EQ(previous_lock_count + 1, SlotLockCount());
137 }
138
SlotLockCount()139 int SlotLockCount() { return mt_receiver_.lock_count(); }
Signal()140 void Signal() { SignalMTLoopback(); }
SignalLockCount()141 int SignalLockCount() { return SignalMTLoopback.lock_count(); }
signal_count()142 int signal_count() { return mt_loop_back_count(); }
InCriticalSection()143 bool InCriticalSection() { return SignalMTLoopback.InCriticalSection(); }
144 };
145
146 // This test will always succeed. However, if the default template instantiation
147 // changes from single threaded to multi threaded it will break the build here.
TEST_F(SigslotDefault,DefaultIsST)148 TEST_F(SigslotDefault, DefaultIsST) {
149 EXPECT_TRUE(TemplateIsST(this));
150 EXPECT_TRUE(TemplateIsST(&signal_));
151 }
152
153 // ST slot, ST signal
TEST_F(SigslotSTSlotTest,STLoopbackTest)154 TEST_F(SigslotSTSlotTest, STLoopbackTest) {
155 SignalSTLoopback();
156 EXPECT_EQ(1, st_loop_back_count());
157 EXPECT_EQ(0, mt_loop_back_count());
158 }
159
160 // ST slot, MT signal
TEST_F(SigslotSTSlotTest,MTLoopbackTest)161 TEST_F(SigslotSTSlotTest, MTLoopbackTest) {
162 SignalMTLoopback();
163 EXPECT_EQ(1, mt_loop_back_count());
164 EXPECT_EQ(0, st_loop_back_count());
165 }
166
167 // ST slot, both ST and MT (separate) signal
TEST_F(SigslotSTSlotTest,AllLoopbackTest)168 TEST_F(SigslotSTSlotTest, AllLoopbackTest) {
169 SignalSTLoopback();
170 SignalMTLoopback();
171 EXPECT_EQ(1, mt_loop_back_count());
172 EXPECT_EQ(1, st_loop_back_count());
173 }
174
TEST_F(SigslotSTSlotTest,Reconnect)175 TEST_F(SigslotSTSlotTest, Reconnect) {
176 SignalSTLoopback();
177 SignalMTLoopback();
178 EXPECT_EQ(1, mt_loop_back_count());
179 EXPECT_EQ(1, st_loop_back_count());
180 Disconnect();
181 SignalSTLoopback();
182 SignalMTLoopback();
183 EXPECT_EQ(1, mt_loop_back_count());
184 EXPECT_EQ(1, st_loop_back_count());
185 Connect();
186 SignalSTLoopback();
187 SignalMTLoopback();
188 EXPECT_EQ(2, mt_loop_back_count());
189 EXPECT_EQ(2, st_loop_back_count());
190 }
191
192 // MT slot, ST signal
TEST_F(SigslotMTSlotTest,STLoopbackTest)193 TEST_F(SigslotMTSlotTest, STLoopbackTest) {
194 SignalSTLoopback();
195 EXPECT_EQ(1, st_loop_back_count());
196 EXPECT_EQ(0, mt_loop_back_count());
197 }
198
199 // MT slot, MT signal
TEST_F(SigslotMTSlotTest,MTLoopbackTest)200 TEST_F(SigslotMTSlotTest, MTLoopbackTest) {
201 SignalMTLoopback();
202 EXPECT_EQ(1, mt_loop_back_count());
203 EXPECT_EQ(0, st_loop_back_count());
204 }
205
206 // MT slot, both ST and MT (separate) signal
TEST_F(SigslotMTSlotTest,AllLoopbackTest)207 TEST_F(SigslotMTSlotTest, AllLoopbackTest) {
208 SignalMTLoopback();
209 SignalSTLoopback();
210 EXPECT_EQ(1, st_loop_back_count());
211 EXPECT_EQ(1, mt_loop_back_count());
212 }
213
214 // Test that locks are acquired and released correctly.
TEST_F(SigslotMTLockTest,LockSanity)215 TEST_F(SigslotMTLockTest, LockSanity) {
216 const int lock_count = SignalLockCount();
217 Signal();
218 EXPECT_FALSE(InCriticalSection());
219 EXPECT_EQ(lock_count + 1, SignalLockCount());
220 EXPECT_EQ(1, signal_count());
221 }
222
223 // Destroy signal and slot in different orders.
TEST(SigslotDestructionOrder,SignalFirst)224 TEST(SigslotDestructionOrder, SignalFirst) {
225 sigslot::signal0<>* signal = new sigslot::signal0<>;
226 SigslotReceiver<>* receiver = new SigslotReceiver<>();
227 receiver->Connect(signal);
228 (*signal)();
229 EXPECT_EQ(1, receiver->signal_count());
230 delete signal;
231 delete receiver;
232 }
233
TEST(SigslotDestructionOrder,SlotFirst)234 TEST(SigslotDestructionOrder, SlotFirst) {
235 sigslot::signal0<>* signal = new sigslot::signal0<>;
236 SigslotReceiver<>* receiver = new SigslotReceiver<>();
237 receiver->Connect(signal);
238 (*signal)();
239 EXPECT_EQ(1, receiver->signal_count());
240
241 delete receiver;
242 (*signal)();
243 delete signal;
244 }
245
246 // Test that if a signal is copied, its slot connections are copied as well.
TEST(SigslotTest,CopyConnectedSignal)247 TEST(SigslotTest, CopyConnectedSignal) {
248 sigslot::signal<> signal;
249 SigslotReceiver<> receiver;
250 receiver.Connect(&signal);
251
252 // Fire the copied signal, expecting the receiver to be notified.
253 sigslot::signal<> copied_signal(signal);
254 copied_signal();
255 EXPECT_EQ(1, receiver.signal_count());
256 }
257
258 // Test that if a slot is copied, its signal connections are copied as well.
TEST(SigslotTest,CopyConnectedSlot)259 TEST(SigslotTest, CopyConnectedSlot) {
260 sigslot::signal<> signal;
261 SigslotReceiver<> receiver;
262 receiver.Connect(&signal);
263
264 // Fire the signal after copying the receiver, expecting the copied receiver
265 // to be notified.
266 SigslotReceiver<> copied_receiver(receiver);
267 signal();
268 EXPECT_EQ(1, copied_receiver.signal_count());
269 }
270
271 // Just used for the test below.
272 class Disconnector : public sigslot::has_slots<> {
273 public:
Disconnector(SigslotReceiver<> * receiver1,SigslotReceiver<> * receiver2)274 Disconnector(SigslotReceiver<>* receiver1, SigslotReceiver<>* receiver2)
275 : receiver1_(receiver1), receiver2_(receiver2) {}
276
Connect(sigslot::signal<> * signal)277 void Connect(sigslot::signal<>* signal) {
278 signal_ = signal;
279 signal->connect(this, &Disconnector::Disconnect);
280 }
281
282 private:
Disconnect()283 void Disconnect() {
284 receiver1_->Disconnect();
285 receiver2_->Disconnect();
286 signal_->disconnect(this);
287 }
288
289 sigslot::signal<>* signal_;
290 SigslotReceiver<>* receiver1_;
291 SigslotReceiver<>* receiver2_;
292 };
293
294 // Test that things work as expected if a signal is disconnected from a slot
295 // while it's firing.
TEST(SigslotTest,DisconnectFromSignalWhileFiring)296 TEST(SigslotTest, DisconnectFromSignalWhileFiring) {
297 sigslot::signal<> signal;
298 SigslotReceiver<> receiver1;
299 SigslotReceiver<> receiver2;
300 SigslotReceiver<> receiver3;
301 Disconnector disconnector(&receiver1, &receiver2);
302
303 // From this ordering, receiver1 should receive the signal, then the
304 // disconnector will be invoked, causing receiver2 to be disconnected before
305 // it receives the signal. And receiver3 should also receive the signal,
306 // since it was never disconnected.
307 receiver1.Connect(&signal);
308 disconnector.Connect(&signal);
309 receiver2.Connect(&signal);
310 receiver3.Connect(&signal);
311 signal();
312
313 EXPECT_EQ(1, receiver1.signal_count());
314 EXPECT_EQ(0, receiver2.signal_count());
315 EXPECT_EQ(1, receiver3.signal_count());
316 }
317
318 // Uses disconnect_all instead of disconnect.
319 class Disconnector2 : public sigslot::has_slots<> {
320 public:
Connect(sigslot::signal<> * signal)321 void Connect(sigslot::signal<>* signal) {
322 signal_ = signal;
323 signal->connect(this, &Disconnector2::Disconnect);
324 }
325
326 private:
Disconnect()327 void Disconnect() { signal_->disconnect_all(); }
328
329 sigslot::signal<>* signal_;
330 };
331
332 // Test that things work as expected if a signal is disconnected from a slot
333 // while it's firing using disconnect_all.
TEST(SigslotTest,CallDisconnectAllWhileSignalFiring)334 TEST(SigslotTest, CallDisconnectAllWhileSignalFiring) {
335 sigslot::signal<> signal;
336 SigslotReceiver<> receiver1;
337 SigslotReceiver<> receiver2;
338 Disconnector2 disconnector;
339
340 // From this ordering, receiver1 should receive the signal, then the
341 // disconnector will be invoked, causing receiver2 to be disconnected before
342 // it receives the signal.
343 receiver1.Connect(&signal);
344 disconnector.Connect(&signal);
345 receiver2.Connect(&signal);
346 signal();
347
348 EXPECT_EQ(1, receiver1.signal_count());
349 EXPECT_EQ(0, receiver2.signal_count());
350 }
351