blob: d7d64b4393545d1e32425b2c030aa102fb4f24b9 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
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
deadbeef8d517c42017-02-19 14:12:24 -0800106 void lock() { ++lock_count_; }
107 void unlock() { ++unlock_count_; }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000108
109 int lock_count() { return lock_count_; }
110
111 bool InCriticalSection() { return lock_count_ != unlock_count_; }
112
113 protected:
114 int lock_count_;
115 int unlock_count_;
116};
117
118typedef SigslotSlotTest<multi_threaded_local_fake,
119 multi_threaded_local_fake> SigslotMTLockBase;
120
121class SigslotMTLockTest : public SigslotMTLockBase {
122 protected:
123 SigslotMTLockTest() {}
124
125 virtual void SetUp() {
126 EXPECT_EQ(0, SlotLockCount());
127 SigslotMTLockBase::SetUp();
128 // Connects to two signals (ST and MT). However,
129 // SlotLockCount() only gets the count for the
130 // MT signal (there are two separate SigslotReceiver which
131 // keep track of their own count).
132 EXPECT_EQ(1, SlotLockCount());
133 }
134 virtual void TearDown() {
135 const int previous_lock_count = SlotLockCount();
136 SigslotMTLockBase::TearDown();
137 // Disconnects from two signals. Note analogous to SetUp().
138 EXPECT_EQ(previous_lock_count + 1, SlotLockCount());
139 }
140
141 int SlotLockCount() { return mt_receiver_.lock_count(); }
142 void Signal() { SignalMTLoopback(); }
143 int SignalLockCount() { return SignalMTLoopback.lock_count(); }
144 int signal_count() { return mt_loop_back_count(); }
145 bool InCriticalSection() { return SignalMTLoopback.InCriticalSection(); }
146};
147
148// This test will always succeed. However, if the default template instantiation
149// changes from single threaded to multi threaded it will break the build here.
150TEST_F(SigslotDefault, DefaultIsST) {
151 EXPECT_TRUE(TemplateIsST(this));
152 EXPECT_TRUE(TemplateIsST(&signal_));
153}
154
155// ST slot, ST signal
156TEST_F(SigslotSTSlotTest, STLoopbackTest) {
157 SignalSTLoopback();
158 EXPECT_EQ(1, st_loop_back_count());
159 EXPECT_EQ(0, mt_loop_back_count());
160}
161
162// ST slot, MT signal
163TEST_F(SigslotSTSlotTest, MTLoopbackTest) {
164 SignalMTLoopback();
165 EXPECT_EQ(1, mt_loop_back_count());
166 EXPECT_EQ(0, st_loop_back_count());
167}
168
169// ST slot, both ST and MT (separate) signal
170TEST_F(SigslotSTSlotTest, AllLoopbackTest) {
171 SignalSTLoopback();
172 SignalMTLoopback();
173 EXPECT_EQ(1, mt_loop_back_count());
174 EXPECT_EQ(1, st_loop_back_count());
175}
176
177TEST_F(SigslotSTSlotTest, Reconnect) {
178 SignalSTLoopback();
179 SignalMTLoopback();
180 EXPECT_EQ(1, mt_loop_back_count());
181 EXPECT_EQ(1, st_loop_back_count());
182 Disconnect();
183 SignalSTLoopback();
184 SignalMTLoopback();
185 EXPECT_EQ(1, mt_loop_back_count());
186 EXPECT_EQ(1, st_loop_back_count());
187 Connect();
188 SignalSTLoopback();
189 SignalMTLoopback();
190 EXPECT_EQ(2, mt_loop_back_count());
191 EXPECT_EQ(2, st_loop_back_count());
192}
193
194// MT slot, ST signal
195TEST_F(SigslotMTSlotTest, STLoopbackTest) {
196 SignalSTLoopback();
197 EXPECT_EQ(1, st_loop_back_count());
198 EXPECT_EQ(0, mt_loop_back_count());
199}
200
201// MT slot, MT signal
202TEST_F(SigslotMTSlotTest, MTLoopbackTest) {
203 SignalMTLoopback();
204 EXPECT_EQ(1, mt_loop_back_count());
205 EXPECT_EQ(0, st_loop_back_count());
206}
207
208// MT slot, both ST and MT (separate) signal
209TEST_F(SigslotMTSlotTest, AllLoopbackTest) {
210 SignalMTLoopback();
211 SignalSTLoopback();
212 EXPECT_EQ(1, st_loop_back_count());
213 EXPECT_EQ(1, mt_loop_back_count());
214}
215
216// Test that locks are acquired and released correctly.
217TEST_F(SigslotMTLockTest, LockSanity) {
218 const int lock_count = SignalLockCount();
219 Signal();
220 EXPECT_FALSE(InCriticalSection());
221 EXPECT_EQ(lock_count + 1, SignalLockCount());
222 EXPECT_EQ(1, signal_count());
223}
224
225// Destroy signal and slot in different orders.
226TEST(DestructionOrder, SignalFirst) {
227 sigslot::signal0<>* signal = new sigslot::signal0<>;
228 SigslotReceiver<>* receiver = new SigslotReceiver<>();
229 receiver->Connect(signal);
230 (*signal)();
231 EXPECT_EQ(1, receiver->signal_count());
232 delete signal;
233 delete receiver;
234}
235
236TEST(DestructionOrder, SlotFirst) {
237 sigslot::signal0<>* signal = new sigslot::signal0<>;
238 SigslotReceiver<>* receiver = new SigslotReceiver<>();
239 receiver->Connect(signal);
240 (*signal)();
241 EXPECT_EQ(1, receiver->signal_count());
242
243 delete receiver;
244 (*signal)();
245 delete signal;
246}