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