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 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} 251