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_(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 62 template<class slot_policy = sigslot::single_threaded, 63 class mt_signal_policy = sigslot::multi_threaded_local> 64 class 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 97 typedef SigslotSlotTest<> SigslotSTSlotTest; 98 typedef SigslotSlotTest<sigslot::multi_threaded_local, 99 sigslot::multi_threaded_local> SigslotMTSlotTest; 100 101 class 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 122 typedef SigslotSlotTest<multi_threaded_local_fake, 123 multi_threaded_local_fake> SigslotMTLockBase; 124 125 class 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. 154 TEST_F(SigslotDefault, DefaultIsST) { 155 EXPECT_TRUE(TemplateIsST(this)); 156 EXPECT_TRUE(TemplateIsST(&signal_)); 157 } 158 159 // ST slot, ST signal 160 TEST_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 167 TEST_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 174 TEST_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 181 TEST_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 199 TEST_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 206 TEST_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 213 TEST_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. 221 TEST_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. 230 TEST(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 240 TEST(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 } 251