xref: /aosp_15_r20/external/webrtc/rtc_base/sigslot_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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