3 * Copyright 2012, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
28 #include "talk/base/sigslot.h"
30 #include "talk/base/gunit.h"
32 // This function, when passed a has_slots or signalx, will break the build if
33 // its threading requirement is not single threaded
34 static bool TemplateIsST(const sigslot::single_threaded* p) {
37 // This function, when passed a has_slots or signalx, will break the build if
38 // its threading requirement is not multi threaded
39 static bool TemplateIsMT(const sigslot::multi_threaded_local* p) {
43 class SigslotDefault : public testing::Test, public sigslot::has_slots<> {
45 sigslot::signal0<> signal_;
48 template<class slot_policy = sigslot::single_threaded,
49 class signal_policy = sigslot::single_threaded>
50 class SigslotReceiver : public sigslot::has_slots<slot_policy> {
52 SigslotReceiver() : signal_(NULL), signal_count_(0) {
57 void Connect(sigslot::signal0<signal_policy>* signal) {
62 &SigslotReceiver<slot_policy, signal_policy>::OnSignal);
66 signal_->disconnect(this);
72 int signal_count() { return signal_count_; }
75 sigslot::signal0<signal_policy>* signal_;
79 template<class slot_policy = sigslot::single_threaded,
80 class mt_signal_policy = sigslot::multi_threaded_local>
81 class SigslotSlotTest : public testing::Test {
84 mt_signal_policy mt_policy;
85 TemplateIsMT(&mt_policy);
88 virtual void SetUp() {
91 virtual void TearDown() {
96 st_receiver_.Disconnect();
97 mt_receiver_.Disconnect();
101 st_receiver_.Connect(&SignalSTLoopback);
102 mt_receiver_.Connect(&SignalMTLoopback);
105 int st_loop_back_count() { return st_receiver_.signal_count(); }
106 int mt_loop_back_count() { return mt_receiver_.signal_count(); }
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_;
114 typedef SigslotSlotTest<> SigslotSTSlotTest;
115 typedef SigslotSlotTest<sigslot::multi_threaded_local,
116 sigslot::multi_threaded_local> SigslotMTSlotTest;
118 class multi_threaded_local_fake : public sigslot::multi_threaded_local {
120 multi_threaded_local_fake() : lock_count_(0), unlock_count_(0) {
123 virtual void lock() {
126 virtual void unlock() {
130 int lock_count() { return lock_count_; }
132 bool InCriticalSection() { return lock_count_ != unlock_count_; }
139 typedef SigslotSlotTest<multi_threaded_local_fake,
140 multi_threaded_local_fake> SigslotMTLockBase;
142 class SigslotMTLockTest : public SigslotMTLockBase {
144 SigslotMTLockTest() {}
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());
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());
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(); }
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.
171 TEST_F(SigslotDefault, DefaultIsST) {
172 EXPECT_TRUE(TemplateIsST(this));
173 EXPECT_TRUE(TemplateIsST(&signal_));
176 // ST slot, ST signal
177 TEST_F(SigslotSTSlotTest, STLoopbackTest) {
179 EXPECT_EQ(1, st_loop_back_count());
180 EXPECT_EQ(0, mt_loop_back_count());
183 // ST slot, MT signal
184 TEST_F(SigslotSTSlotTest, MTLoopbackTest) {
186 EXPECT_EQ(1, mt_loop_back_count());
187 EXPECT_EQ(0, st_loop_back_count());
190 // ST slot, both ST and MT (separate) signal
191 TEST_F(SigslotSTSlotTest, AllLoopbackTest) {
194 EXPECT_EQ(1, mt_loop_back_count());
195 EXPECT_EQ(1, st_loop_back_count());
198 TEST_F(SigslotSTSlotTest, Reconnect) {
201 EXPECT_EQ(1, mt_loop_back_count());
202 EXPECT_EQ(1, st_loop_back_count());
206 EXPECT_EQ(1, mt_loop_back_count());
207 EXPECT_EQ(1, st_loop_back_count());
211 EXPECT_EQ(2, mt_loop_back_count());
212 EXPECT_EQ(2, st_loop_back_count());
215 // MT slot, ST signal
216 TEST_F(SigslotMTSlotTest, STLoopbackTest) {
218 EXPECT_EQ(1, st_loop_back_count());
219 EXPECT_EQ(0, mt_loop_back_count());
222 // MT slot, MT signal
223 TEST_F(SigslotMTSlotTest, MTLoopbackTest) {
225 EXPECT_EQ(1, mt_loop_back_count());
226 EXPECT_EQ(0, st_loop_back_count());
229 // MT slot, both ST and MT (separate) signal
230 TEST_F(SigslotMTSlotTest, AllLoopbackTest) {
233 EXPECT_EQ(1, st_loop_back_count());
234 EXPECT_EQ(1, mt_loop_back_count());
237 // Test that locks are acquired and released correctly.
238 TEST_F(SigslotMTLockTest, LockSanity) {
239 const int lock_count = SignalLockCount();
241 EXPECT_FALSE(InCriticalSection());
242 EXPECT_EQ(lock_count + 1, SignalLockCount());
243 EXPECT_EQ(1, signal_count());
246 // Destroy signal and slot in different orders.
247 TEST(DestructionOrder, SignalFirst) {
248 sigslot::signal0<>* signal = new sigslot::signal0<>;
249 SigslotReceiver<>* receiver = new SigslotReceiver<>();
250 receiver->Connect(signal);
252 EXPECT_EQ(1, receiver->signal_count());
257 TEST(DestructionOrder, SlotFirst) {
258 sigslot::signal0<>* signal = new sigslot::signal0<>;
259 SigslotReceiver<>* receiver = new SigslotReceiver<>();
260 receiver->Connect(signal);
262 EXPECT_EQ(1, receiver->signal_count());