blob: e9fdba503c2123f3867d9bbfdba2e2e45cd36388 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:261/*
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
Artem Titove41c4332018-07-25 13:04:2811#include "rtc_base/third_party/sigslot/sigslot.h"
Yves Gerey3e707812018-11-28 15:47:4912
Yves Gerey3e707812018-11-28 15:47:4913#include "test/gtest.h"
henrike@webrtc.orgf0488722014-05-13 18:00:2614
15// This function, when passed a has_slots or signalx, will break the build if
16// its threading requirement is not single threaded
17static 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
22static bool TemplateIsMT(const sigslot::multi_threaded_local* p) {
23 return true;
24}
25
Mirko Bonadei6a489f22019-04-09 13:11:1226class SigslotDefault : public ::testing::Test, public sigslot::has_slots<> {
henrike@webrtc.orgf0488722014-05-13 18:00:2627 protected:
28 sigslot::signal0<> signal_;
29};
30
Yves Gerey665174f2018-06-19 13:03:0531template <class slot_policy = sigslot::single_threaded,
32 class signal_policy = sigslot::single_threaded>
henrike@webrtc.orgf0488722014-05-13 18:00:2633class SigslotReceiver : public sigslot::has_slots<slot_policy> {
34 public:
deadbeef37f5ecf2017-02-27 22:06:4135 SigslotReceiver() : signal_(nullptr), signal_count_(0) {}
Yves Gerey665174f2018-06-19 13:03:0536 ~SigslotReceiver() {}
henrike@webrtc.orgf0488722014-05-13 18:00:2637
deadbeef8b1d8622017-04-29 07:27:0438 // Provide copy constructor so that tests can exercise the has_slots copy
39 // constructor.
40 SigslotReceiver(const SigslotReceiver&) = default;
41
henrike@webrtc.orgf0488722014-05-13 18:00:2642 void Connect(sigslot::signal0<signal_policy>* signal) {
Yves Gerey665174f2018-06-19 13:03:0543 if (!signal)
44 return;
henrike@webrtc.orgf0488722014-05-13 18:00:2645 Disconnect();
46 signal_ = signal;
47 signal->connect(this,
48 &SigslotReceiver<slot_policy, signal_policy>::OnSignal);
49 }
50 void Disconnect() {
Yves Gerey665174f2018-06-19 13:03:0551 if (!signal_)
52 return;
henrike@webrtc.orgf0488722014-05-13 18:00:2653 signal_->disconnect(this);
deadbeef37f5ecf2017-02-27 22:06:4154 signal_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:2655 }
Yves Gerey665174f2018-06-19 13:03:0556 void OnSignal() { ++signal_count_; }
henrike@webrtc.orgf0488722014-05-13 18:00:2657 int signal_count() { return signal_count_; }
58
59 private:
60 sigslot::signal0<signal_policy>* signal_;
61 int signal_count_;
62};
63
Yves Gerey665174f2018-06-19 13:03:0564template <class slot_policy = sigslot::single_threaded,
65 class mt_signal_policy = sigslot::multi_threaded_local>
Mirko Bonadei6a489f22019-04-09 13:11:1266class SigslotSlotTest : public ::testing::Test {
henrike@webrtc.orgf0488722014-05-13 18:00:2667 protected:
68 SigslotSlotTest() {
69 mt_signal_policy mt_policy;
70 TemplateIsMT(&mt_policy);
71 }
72
Yves Gerey665174f2018-06-19 13:03:0573 virtual void SetUp() { Connect(); }
74 virtual void TearDown() { Disconnect(); }
henrike@webrtc.orgf0488722014-05-13 18:00:2675
76 void Disconnect() {
77 st_receiver_.Disconnect();
78 mt_receiver_.Disconnect();
79 }
80
81 void Connect() {
82 st_receiver_.Connect(&SignalSTLoopback);
83 mt_receiver_.Connect(&SignalMTLoopback);
84 }
85
86 int st_loop_back_count() { return st_receiver_.signal_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
95typedef SigslotSlotTest<> SigslotSTSlotTest;
96typedef SigslotSlotTest<sigslot::multi_threaded_local,
Yves Gerey665174f2018-06-19 13:03:0597 sigslot::multi_threaded_local>
98 SigslotMTSlotTest;
henrike@webrtc.orgf0488722014-05-13 18:00:2699
100class multi_threaded_local_fake : public sigslot::multi_threaded_local {
101 public:
Yves Gerey665174f2018-06-19 13:03:05102 multi_threaded_local_fake() : lock_count_(0), unlock_count_(0) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26103
deadbeef8d517c42017-02-19 22:12:24104 void lock() { ++lock_count_; }
105 void unlock() { ++unlock_count_; }
henrike@webrtc.orgf0488722014-05-13 18:00:26106
107 int lock_count() { return lock_count_; }
108
109 bool InCriticalSection() { return lock_count_ != unlock_count_; }
110
111 protected:
112 int lock_count_;
113 int unlock_count_;
114};
115
Yves Gerey665174f2018-06-19 13:03:05116typedef SigslotSlotTest<multi_threaded_local_fake, multi_threaded_local_fake>
117 SigslotMTLockBase;
henrike@webrtc.orgf0488722014-05-13 18:00:26118
119class SigslotMTLockTest : public SigslotMTLockBase {
120 protected:
121 SigslotMTLockTest() {}
122
Steve Anton9de3aac2017-10-24 17:08:26123 void SetUp() override {
henrike@webrtc.orgf0488722014-05-13 18:00:26124 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 }
Steve Anton9de3aac2017-10-24 17:08:26132 void TearDown() override {
henrike@webrtc.orgf0488722014-05-13 18:00:26133 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
139 int SlotLockCount() { return mt_receiver_.lock_count(); }
140 void Signal() { SignalMTLoopback(); }
141 int SignalLockCount() { return SignalMTLoopback.lock_count(); }
142 int signal_count() { return mt_loop_back_count(); }
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.
148TEST_F(SigslotDefault, DefaultIsST) {
149 EXPECT_TRUE(TemplateIsST(this));
150 EXPECT_TRUE(TemplateIsST(&signal_));
151}
152
153// ST slot, ST signal
154TEST_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
161TEST_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
168TEST_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
175TEST_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
193TEST_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
200TEST_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
207TEST_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.
215TEST_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.
deadbeef8b1d8622017-04-29 07:27:04224TEST(SigslotDestructionOrder, SignalFirst) {
henrike@webrtc.orgf0488722014-05-13 18:00:26225 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
deadbeef8b1d8622017-04-29 07:27:04234TEST(SigslotDestructionOrder, SlotFirst) {
henrike@webrtc.orgf0488722014-05-13 18:00:26235 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}
deadbeef8b1d8622017-04-29 07:27:04245
246// Test that if a signal is copied, its slot connections are copied as well.
247TEST(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.
259TEST(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}
deadbeef4483af32017-05-12 15:44:38270
271// Just used for the test below.
272class Disconnector : public sigslot::has_slots<> {
273 public:
274 Disconnector(SigslotReceiver<>* receiver1, SigslotReceiver<>* receiver2)
275 : receiver1_(receiver1), receiver2_(receiver2) {}
276
277 void Connect(sigslot::signal<>* signal) {
278 signal_ = signal;
279 signal->connect(this, &Disconnector::Disconnect);
280 }
281
282 private:
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.
296TEST(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.
319class Disconnector2 : public sigslot::has_slots<> {
320 public:
321 void Connect(sigslot::signal<>* signal) {
322 signal_ = signal;
323 signal->connect(this, &Disconnector2::Disconnect);
324 }
325
326 private:
Yves Gerey665174f2018-06-19 13:03:05327 void Disconnect() { signal_->disconnect_all(); }
deadbeef4483af32017-05-12 15:44:38328
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.
334TEST(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}