1 /* 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 34 static 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 39 static bool TemplateIsMT(const sigslot::multi_threaded_local* p) { 40 return true; 41 } 42 43 class SigslotDefault : public testing::Test, public sigslot::has_slots<> { 44 protected: 45 sigslot::signal0<> signal_; 46 }; 47 48 template<class slot_policy = sigslot::single_threaded, 49 class signal_policy = sigslot::single_threaded> 50 class 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 79 template<class slot_policy = sigslot::single_threaded, 80 class mt_signal_policy = sigslot::multi_threaded_local> 81 class 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 114 typedef SigslotSlotTest<> SigslotSTSlotTest; 115 typedef SigslotSlotTest<sigslot::multi_threaded_local, 116 sigslot::multi_threaded_local> SigslotMTSlotTest; 117 118 class 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 139 typedef SigslotSlotTest<multi_threaded_local_fake, 140 multi_threaded_local_fake> SigslotMTLockBase; 141 142 class 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. 171 TEST_F(SigslotDefault, DefaultIsST) { 172 EXPECT_TRUE(TemplateIsST(this)); 173 EXPECT_TRUE(TemplateIsST(&signal_)); 174 } 175 176 // ST slot, ST signal 177 TEST_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 184 TEST_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 191 TEST_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 198 TEST_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 216 TEST_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 223 TEST_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 230 TEST_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. 238 TEST_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. 247 TEST(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 257 TEST(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 } 268