blob: 4d3041d1326ecac9e5a61bf353bcbbf8f52c82d2 [file] [log] [blame]
henrike@webrtc.orgf7795df2014-05-13 18:00:26 +00001/*
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
17static 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
22static bool TemplateIsMT(const sigslot::multi_threaded_local* p) {
23 return true;
24}
25
26class SigslotDefault : public testing::Test, public sigslot::has_slots<> {
27 protected:
28 sigslot::signal0<> signal_;
29};
30
31template<class slot_policy = sigslot::single_threaded,
32 class signal_policy = sigslot::single_threaded>
33class SigslotReceiver : public sigslot::has_slots<slot_policy> {
34 public:
35 SigslotReceiver() : signal_(NULL), signal_count_(0) {
36 }
37 ~SigslotReceiver() {
38 }
39
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 }
47 void Disconnect() {
48 if (!signal_) return;
49 signal_->disconnect(this);
50 signal_ = NULL;
51 }
52 void OnSignal() {
53 ++signal_count_;
54 }
55 int signal_count() { return signal_count_; }
56
57 private:
58 sigslot::signal0<signal_policy>* signal_;
59 int signal_count_;
60};
61
62template<class slot_policy = sigslot::single_threaded,
63 class mt_signal_policy = sigslot::multi_threaded_local>
64class SigslotSlotTest : public testing::Test {
65 protected:
66 SigslotSlotTest() {
67 mt_signal_policy mt_policy;
68 TemplateIsMT(&mt_policy);
69 }
70
71 virtual void SetUp() {
72 Connect();
73 }
74 virtual void TearDown() {
75 Disconnect();
76 }
77
78 void Disconnect() {
79 st_receiver_.Disconnect();
80 mt_receiver_.Disconnect();
81 }
82
83 void Connect() {
84 st_receiver_.Connect(&SignalSTLoopback);
85 mt_receiver_.Connect(&SignalMTLoopback);
86 }
87
88 int st_loop_back_count() { return st_receiver_.signal_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
97typedef SigslotSlotTest<> SigslotSTSlotTest;
98typedef SigslotSlotTest<sigslot::multi_threaded_local,
99 sigslot::multi_threaded_local> SigslotMTSlotTest;
100
101class multi_threaded_local_fake : public sigslot::multi_threaded_local {
102 public:
103 multi_threaded_local_fake() : lock_count_(0), unlock_count_(0) {
104 }
105
106 virtual void lock() {
107 ++lock_count_;
108 }
109 virtual void unlock() {
110 ++unlock_count_;
111 }
112
113 int lock_count() { return lock_count_; }
114
115 bool InCriticalSection() { return lock_count_ != unlock_count_; }
116
117 protected:
118 int lock_count_;
119 int unlock_count_;
120};
121
122typedef SigslotSlotTest<multi_threaded_local_fake,
123 multi_threaded_local_fake> SigslotMTLockBase;
124
125class SigslotMTLockTest : public SigslotMTLockBase {
126 protected:
127 SigslotMTLockTest() {}
128
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 }
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
145 int SlotLockCount() { return mt_receiver_.lock_count(); }
146 void Signal() { SignalMTLoopback(); }
147 int SignalLockCount() { return SignalMTLoopback.lock_count(); }
148 int signal_count() { return mt_loop_back_count(); }
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.
154TEST_F(SigslotDefault, DefaultIsST) {
155 EXPECT_TRUE(TemplateIsST(this));
156 EXPECT_TRUE(TemplateIsST(&signal_));
157}
158
159// ST slot, ST signal
160TEST_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
167TEST_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
174TEST_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
181TEST_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
199TEST_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
206TEST_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
213TEST_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.
221TEST_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.
230TEST(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
240TEST(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}