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