blob: 62b03c24d6aa243876b6aa649588b2bb7a413fda [file] [log] [blame]
henrike@webrtc.org0e118e72013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2012, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/base/sigslot.h"
29
30#include "talk/base/gunit.h"
31
32// This function, when passed a has_slots or signalx, will break the build if
33// its threading requirement is not single threaded
34static bool TemplateIsST(const sigslot::single_threaded* p) {
35 return true;
36}
37// This function, when passed a has_slots or signalx, will break the build if
38// its threading requirement is not multi threaded
39static bool TemplateIsMT(const sigslot::multi_threaded_local* p) {
40 return true;
41}
42
43class SigslotDefault : public testing::Test, public sigslot::has_slots<> {
44 protected:
45 sigslot::signal0<> signal_;
46};
47
48template<class slot_policy = sigslot::single_threaded,
49 class signal_policy = sigslot::single_threaded>
50class SigslotReceiver : public sigslot::has_slots<slot_policy> {
51 public:
52 SigslotReceiver() : signal_(NULL), signal_count_(0) {
53 }
54 ~SigslotReceiver() {
55 }
56
57 void Connect(sigslot::signal0<signal_policy>* signal) {
58 if (!signal) return;
59 Disconnect();
60 signal_ = signal;
61 signal->connect(this,
62 &SigslotReceiver<slot_policy, signal_policy>::OnSignal);
63 }
64 void Disconnect() {
65 if (!signal_) return;
66 signal_->disconnect(this);
67 signal_ = NULL;
68 }
69 void OnSignal() {
70 ++signal_count_;
71 }
72 int signal_count() { return signal_count_; }
73
74 private:
75 sigslot::signal0<signal_policy>* signal_;
76 int signal_count_;
77};
78
79template<class slot_policy = sigslot::single_threaded,
80 class mt_signal_policy = sigslot::multi_threaded_local>
81class SigslotSlotTest : public testing::Test {
82 protected:
83 SigslotSlotTest() {
84 mt_signal_policy mt_policy;
85 TemplateIsMT(&mt_policy);
86 }
87
88 virtual void SetUp() {
89 Connect();
90 }
91 virtual void TearDown() {
92 Disconnect();
93 }
94
95 void Disconnect() {
96 st_receiver_.Disconnect();
97 mt_receiver_.Disconnect();
98 }
99
100 void Connect() {
101 st_receiver_.Connect(&SignalSTLoopback);
102 mt_receiver_.Connect(&SignalMTLoopback);
103 }
104
105 int st_loop_back_count() { return st_receiver_.signal_count(); }
106 int mt_loop_back_count() { return mt_receiver_.signal_count(); }
107
108 sigslot::signal0<> SignalSTLoopback;
109 SigslotReceiver<slot_policy, sigslot::single_threaded> st_receiver_;
110 sigslot::signal0<mt_signal_policy> SignalMTLoopback;
111 SigslotReceiver<slot_policy, mt_signal_policy> mt_receiver_;
112};
113
114typedef SigslotSlotTest<> SigslotSTSlotTest;
115typedef SigslotSlotTest<sigslot::multi_threaded_local,
116 sigslot::multi_threaded_local> SigslotMTSlotTest;
117
118class multi_threaded_local_fake : public sigslot::multi_threaded_local {
119 public:
120 multi_threaded_local_fake() : lock_count_(0), unlock_count_(0) {
121 }
122
123 virtual void lock() {
124 ++lock_count_;
125 }
126 virtual void unlock() {
127 ++unlock_count_;
128 }
129
130 int lock_count() { return lock_count_; }
131
132 bool InCriticalSection() { return lock_count_ != unlock_count_; }
133
134 protected:
135 int lock_count_;
136 int unlock_count_;
137};
138
139typedef SigslotSlotTest<multi_threaded_local_fake,
140 multi_threaded_local_fake> SigslotMTLockBase;
141
142class SigslotMTLockTest : public SigslotMTLockBase {
143 protected:
144 SigslotMTLockTest() {}
145
146 virtual void SetUp() {
147 EXPECT_EQ(0, SlotLockCount());
148 SigslotMTLockBase::SetUp();
149 // Connects to two signals (ST and MT). However,
150 // SlotLockCount() only gets the count for the
151 // MT signal (there are two separate SigslotReceiver which
152 // keep track of their own count).
153 EXPECT_EQ(1, SlotLockCount());
154 }
155 virtual void TearDown() {
156 const int previous_lock_count = SlotLockCount();
157 SigslotMTLockBase::TearDown();
158 // Disconnects from two signals. Note analogous to SetUp().
159 EXPECT_EQ(previous_lock_count + 1, SlotLockCount());
160 }
161
162 int SlotLockCount() { return mt_receiver_.lock_count(); }
163 void Signal() { SignalMTLoopback(); }
164 int SignalLockCount() { return SignalMTLoopback.lock_count(); }
165 int signal_count() { return mt_loop_back_count(); }
166 bool InCriticalSection() { return SignalMTLoopback.InCriticalSection(); }
167};
168
169// This test will always succeed. However, if the default template instantiation
170// changes from single threaded to multi threaded it will break the build here.
171TEST_F(SigslotDefault, DefaultIsST) {
172 EXPECT_TRUE(TemplateIsST(this));
173 EXPECT_TRUE(TemplateIsST(&signal_));
174}
175
176// ST slot, ST signal
177TEST_F(SigslotSTSlotTest, STLoopbackTest) {
178 SignalSTLoopback();
179 EXPECT_EQ(1, st_loop_back_count());
180 EXPECT_EQ(0, mt_loop_back_count());
181}
182
183// ST slot, MT signal
184TEST_F(SigslotSTSlotTest, MTLoopbackTest) {
185 SignalMTLoopback();
186 EXPECT_EQ(1, mt_loop_back_count());
187 EXPECT_EQ(0, st_loop_back_count());
188}
189
190// ST slot, both ST and MT (separate) signal
191TEST_F(SigslotSTSlotTest, AllLoopbackTest) {
192 SignalSTLoopback();
193 SignalMTLoopback();
194 EXPECT_EQ(1, mt_loop_back_count());
195 EXPECT_EQ(1, st_loop_back_count());
196}
197
198TEST_F(SigslotSTSlotTest, Reconnect) {
199 SignalSTLoopback();
200 SignalMTLoopback();
201 EXPECT_EQ(1, mt_loop_back_count());
202 EXPECT_EQ(1, st_loop_back_count());
203 Disconnect();
204 SignalSTLoopback();
205 SignalMTLoopback();
206 EXPECT_EQ(1, mt_loop_back_count());
207 EXPECT_EQ(1, st_loop_back_count());
208 Connect();
209 SignalSTLoopback();
210 SignalMTLoopback();
211 EXPECT_EQ(2, mt_loop_back_count());
212 EXPECT_EQ(2, st_loop_back_count());
213}
214
215// MT slot, ST signal
216TEST_F(SigslotMTSlotTest, STLoopbackTest) {
217 SignalSTLoopback();
218 EXPECT_EQ(1, st_loop_back_count());
219 EXPECT_EQ(0, mt_loop_back_count());
220}
221
222// MT slot, MT signal
223TEST_F(SigslotMTSlotTest, MTLoopbackTest) {
224 SignalMTLoopback();
225 EXPECT_EQ(1, mt_loop_back_count());
226 EXPECT_EQ(0, st_loop_back_count());
227}
228
229// MT slot, both ST and MT (separate) signal
230TEST_F(SigslotMTSlotTest, AllLoopbackTest) {
231 SignalMTLoopback();
232 SignalSTLoopback();
233 EXPECT_EQ(1, st_loop_back_count());
234 EXPECT_EQ(1, mt_loop_back_count());
235}
236
237// Test that locks are acquired and released correctly.
238TEST_F(SigslotMTLockTest, LockSanity) {
239 const int lock_count = SignalLockCount();
240 Signal();
241 EXPECT_FALSE(InCriticalSection());
242 EXPECT_EQ(lock_count + 1, SignalLockCount());
243 EXPECT_EQ(1, signal_count());
244}
245
246// Destroy signal and slot in different orders.
247TEST(DestructionOrder, SignalFirst) {
248 sigslot::signal0<>* signal = new sigslot::signal0<>;
249 SigslotReceiver<>* receiver = new SigslotReceiver<>();
250 receiver->Connect(signal);
251 (*signal)();
252 EXPECT_EQ(1, receiver->signal_count());
253 delete signal;
254 delete receiver;
255}
256
257TEST(DestructionOrder, SlotFirst) {
258 sigslot::signal0<>* signal = new sigslot::signal0<>;
259 SigslotReceiver<>* receiver = new SigslotReceiver<>();
260 receiver->Connect(signal);
261 (*signal)();
262 EXPECT_EQ(1, receiver->signal_count());
263
264 delete receiver;
265 (*signal)();
266 delete signal;
267}