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