• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "webrtc/base/sigslot.h"
12 
13 #include "webrtc/base/gunit.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_(NULL), signal_count_(0) {
36   }
~SigslotReceiver()37   ~SigslotReceiver() {
38   }
39 
Connect(sigslot::signal0<signal_policy> * signal)40   void Connect(sigslot::signal0<signal_policy>* signal) {
41     if (!signal) return;
42     Disconnect();
43     signal_ = signal;
44     signal->connect(this,
45                     &SigslotReceiver<slot_policy, signal_policy>::OnSignal);
46   }
Disconnect()47   void Disconnect() {
48     if (!signal_) return;
49     signal_->disconnect(this);
50     signal_ = NULL;
51   }
OnSignal()52   void OnSignal() {
53     ++signal_count_;
54   }
signal_count()55   int signal_count() { return signal_count_; }
56 
57  private:
58   sigslot::signal0<signal_policy>* signal_;
59   int signal_count_;
60 };
61 
62 template<class slot_policy = sigslot::single_threaded,
63          class mt_signal_policy = sigslot::multi_threaded_local>
64 class SigslotSlotTest : public testing::Test {
65  protected:
SigslotSlotTest()66   SigslotSlotTest() {
67     mt_signal_policy mt_policy;
68     TemplateIsMT(&mt_policy);
69   }
70 
SetUp()71   virtual void SetUp() {
72     Connect();
73   }
TearDown()74   virtual void TearDown() {
75     Disconnect();
76   }
77 
Disconnect()78   void Disconnect() {
79     st_receiver_.Disconnect();
80     mt_receiver_.Disconnect();
81   }
82 
Connect()83   void Connect() {
84     st_receiver_.Connect(&SignalSTLoopback);
85     mt_receiver_.Connect(&SignalMTLoopback);
86   }
87 
st_loop_back_count()88   int st_loop_back_count() { return st_receiver_.signal_count(); }
mt_loop_back_count()89   int mt_loop_back_count() { return mt_receiver_.signal_count(); }
90 
91   sigslot::signal0<> SignalSTLoopback;
92   SigslotReceiver<slot_policy, sigslot::single_threaded> st_receiver_;
93   sigslot::signal0<mt_signal_policy> SignalMTLoopback;
94   SigslotReceiver<slot_policy, mt_signal_policy> mt_receiver_;
95 };
96 
97 typedef SigslotSlotTest<> SigslotSTSlotTest;
98 typedef SigslotSlotTest<sigslot::multi_threaded_local,
99                         sigslot::multi_threaded_local> 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   }
105 
lock()106   virtual void lock() {
107     ++lock_count_;
108   }
unlock()109   virtual void unlock() {
110     ++unlock_count_;
111   }
112 
lock_count()113   int lock_count() { return lock_count_; }
114 
InCriticalSection()115   bool InCriticalSection() { return lock_count_ != unlock_count_; }
116 
117  protected:
118   int lock_count_;
119   int unlock_count_;
120 };
121 
122 typedef SigslotSlotTest<multi_threaded_local_fake,
123                         multi_threaded_local_fake> SigslotMTLockBase;
124 
125 class SigslotMTLockTest : public SigslotMTLockBase {
126  protected:
SigslotMTLockTest()127   SigslotMTLockTest() {}
128 
SetUp()129   virtual void SetUp() {
130     EXPECT_EQ(0, SlotLockCount());
131     SigslotMTLockBase::SetUp();
132     // Connects to two signals (ST and MT). However,
133     // SlotLockCount() only gets the count for the
134     // MT signal (there are two separate SigslotReceiver which
135     // keep track of their own count).
136     EXPECT_EQ(1, SlotLockCount());
137   }
TearDown()138   virtual void TearDown() {
139     const int previous_lock_count = SlotLockCount();
140     SigslotMTLockBase::TearDown();
141     // Disconnects from two signals. Note analogous to SetUp().
142     EXPECT_EQ(previous_lock_count + 1, SlotLockCount());
143   }
144 
SlotLockCount()145   int SlotLockCount() { return mt_receiver_.lock_count(); }
Signal()146   void Signal() { SignalMTLoopback(); }
SignalLockCount()147   int SignalLockCount() { return SignalMTLoopback.lock_count(); }
signal_count()148   int signal_count() { return mt_loop_back_count(); }
InCriticalSection()149   bool InCriticalSection() { return SignalMTLoopback.InCriticalSection(); }
150 };
151 
152 // This test will always succeed. However, if the default template instantiation
153 // changes from single threaded to multi threaded it will break the build here.
TEST_F(SigslotDefault,DefaultIsST)154 TEST_F(SigslotDefault, DefaultIsST) {
155   EXPECT_TRUE(TemplateIsST(this));
156   EXPECT_TRUE(TemplateIsST(&signal_));
157 }
158 
159 // ST slot, ST signal
TEST_F(SigslotSTSlotTest,STLoopbackTest)160 TEST_F(SigslotSTSlotTest, STLoopbackTest) {
161   SignalSTLoopback();
162   EXPECT_EQ(1, st_loop_back_count());
163   EXPECT_EQ(0, mt_loop_back_count());
164 }
165 
166 // ST slot, MT signal
TEST_F(SigslotSTSlotTest,MTLoopbackTest)167 TEST_F(SigslotSTSlotTest, MTLoopbackTest) {
168   SignalMTLoopback();
169   EXPECT_EQ(1, mt_loop_back_count());
170   EXPECT_EQ(0, st_loop_back_count());
171 }
172 
173 // ST slot, both ST and MT (separate) signal
TEST_F(SigslotSTSlotTest,AllLoopbackTest)174 TEST_F(SigslotSTSlotTest, AllLoopbackTest) {
175   SignalSTLoopback();
176   SignalMTLoopback();
177   EXPECT_EQ(1, mt_loop_back_count());
178   EXPECT_EQ(1, st_loop_back_count());
179 }
180 
TEST_F(SigslotSTSlotTest,Reconnect)181 TEST_F(SigslotSTSlotTest, Reconnect) {
182   SignalSTLoopback();
183   SignalMTLoopback();
184   EXPECT_EQ(1, mt_loop_back_count());
185   EXPECT_EQ(1, st_loop_back_count());
186   Disconnect();
187   SignalSTLoopback();
188   SignalMTLoopback();
189   EXPECT_EQ(1, mt_loop_back_count());
190   EXPECT_EQ(1, st_loop_back_count());
191   Connect();
192   SignalSTLoopback();
193   SignalMTLoopback();
194   EXPECT_EQ(2, mt_loop_back_count());
195   EXPECT_EQ(2, st_loop_back_count());
196 }
197 
198 // MT slot, ST signal
TEST_F(SigslotMTSlotTest,STLoopbackTest)199 TEST_F(SigslotMTSlotTest, STLoopbackTest) {
200   SignalSTLoopback();
201   EXPECT_EQ(1, st_loop_back_count());
202   EXPECT_EQ(0, mt_loop_back_count());
203 }
204 
205 // MT slot, MT signal
TEST_F(SigslotMTSlotTest,MTLoopbackTest)206 TEST_F(SigslotMTSlotTest, MTLoopbackTest) {
207   SignalMTLoopback();
208   EXPECT_EQ(1, mt_loop_back_count());
209   EXPECT_EQ(0, st_loop_back_count());
210 }
211 
212 // MT slot, both ST and MT (separate) signal
TEST_F(SigslotMTSlotTest,AllLoopbackTest)213 TEST_F(SigslotMTSlotTest, AllLoopbackTest) {
214   SignalMTLoopback();
215   SignalSTLoopback();
216   EXPECT_EQ(1, st_loop_back_count());
217   EXPECT_EQ(1, mt_loop_back_count());
218 }
219 
220 // Test that locks are acquired and released correctly.
TEST_F(SigslotMTLockTest,LockSanity)221 TEST_F(SigslotMTLockTest, LockSanity) {
222   const int lock_count = SignalLockCount();
223   Signal();
224   EXPECT_FALSE(InCriticalSection());
225   EXPECT_EQ(lock_count + 1, SignalLockCount());
226   EXPECT_EQ(1, signal_count());
227 }
228 
229 // Destroy signal and slot in different orders.
TEST(DestructionOrder,SignalFirst)230 TEST(DestructionOrder, SignalFirst) {
231   sigslot::signal0<>* signal = new sigslot::signal0<>;
232   SigslotReceiver<>* receiver = new SigslotReceiver<>();
233   receiver->Connect(signal);
234   (*signal)();
235   EXPECT_EQ(1, receiver->signal_count());
236   delete signal;
237   delete receiver;
238 }
239 
TEST(DestructionOrder,SlotFirst)240 TEST(DestructionOrder, SlotFirst) {
241   sigslot::signal0<>* signal = new sigslot::signal0<>;
242   SigslotReceiver<>* receiver = new SigslotReceiver<>();
243   receiver->Connect(signal);
244   (*signal)();
245   EXPECT_EQ(1, receiver->signal_count());
246 
247   delete receiver;
248   (*signal)();
249   delete signal;
250 }
251