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