blob: cb773363101b93e3f0ee05f3c3208ddbc7a69cea [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:
deadbeef37f5ecf2017-02-27 14:06:41 -080035 SigslotReceiver() : signal_(nullptr), signal_count_(0) {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036 ~SigslotReceiver() {
37 }
38
39 void Connect(sigslot::signal0<signal_policy>* signal) {
40 if (!signal) return;
41 Disconnect();
42 signal_ = signal;
43 signal->connect(this,
44 &SigslotReceiver<slot_policy, signal_policy>::OnSignal);
45 }
46 void Disconnect() {
47 if (!signal_) return;
48 signal_->disconnect(this);
deadbeef37f5ecf2017-02-27 14:06:41 -080049 signal_ = nullptr;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000050 }
51 void OnSignal() {
52 ++signal_count_;
53 }
54 int signal_count() { return signal_count_; }
55
56 private:
57 sigslot::signal0<signal_policy>* signal_;
58 int signal_count_;
59};
60
61template<class slot_policy = sigslot::single_threaded,
62 class mt_signal_policy = sigslot::multi_threaded_local>
63class SigslotSlotTest : public testing::Test {
64 protected:
65 SigslotSlotTest() {
66 mt_signal_policy mt_policy;
67 TemplateIsMT(&mt_policy);
68 }
69
70 virtual void SetUp() {
71 Connect();
72 }
73 virtual void TearDown() {
74 Disconnect();
75 }
76
77 void Disconnect() {
78 st_receiver_.Disconnect();
79 mt_receiver_.Disconnect();
80 }
81
82 void Connect() {
83 st_receiver_.Connect(&SignalSTLoopback);
84 mt_receiver_.Connect(&SignalMTLoopback);
85 }
86
87 int st_loop_back_count() { return st_receiver_.signal_count(); }
88 int mt_loop_back_count() { return mt_receiver_.signal_count(); }
89
90 sigslot::signal0<> SignalSTLoopback;
91 SigslotReceiver<slot_policy, sigslot::single_threaded> st_receiver_;
92 sigslot::signal0<mt_signal_policy> SignalMTLoopback;
93 SigslotReceiver<slot_policy, mt_signal_policy> mt_receiver_;
94};
95
96typedef SigslotSlotTest<> SigslotSTSlotTest;
97typedef SigslotSlotTest<sigslot::multi_threaded_local,
98 sigslot::multi_threaded_local> SigslotMTSlotTest;
99
100class multi_threaded_local_fake : public sigslot::multi_threaded_local {
101 public:
102 multi_threaded_local_fake() : lock_count_(0), unlock_count_(0) {
103 }
104
deadbeef8d517c42017-02-19 14:12:24 -0800105 void lock() { ++lock_count_; }
106 void unlock() { ++unlock_count_; }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000107
108 int lock_count() { return lock_count_; }
109
110 bool InCriticalSection() { return lock_count_ != unlock_count_; }
111
112 protected:
113 int lock_count_;
114 int unlock_count_;
115};
116
117typedef SigslotSlotTest<multi_threaded_local_fake,
118 multi_threaded_local_fake> SigslotMTLockBase;
119
120class SigslotMTLockTest : public SigslotMTLockBase {
121 protected:
122 SigslotMTLockTest() {}
123
124 virtual void SetUp() {
125 EXPECT_EQ(0, SlotLockCount());
126 SigslotMTLockBase::SetUp();
127 // Connects to two signals (ST and MT). However,
128 // SlotLockCount() only gets the count for the
129 // MT signal (there are two separate SigslotReceiver which
130 // keep track of their own count).
131 EXPECT_EQ(1, SlotLockCount());
132 }
133 virtual void TearDown() {
134 const int previous_lock_count = SlotLockCount();
135 SigslotMTLockBase::TearDown();
136 // Disconnects from two signals. Note analogous to SetUp().
137 EXPECT_EQ(previous_lock_count + 1, SlotLockCount());
138 }
139
140 int SlotLockCount() { return mt_receiver_.lock_count(); }
141 void Signal() { SignalMTLoopback(); }
142 int SignalLockCount() { return SignalMTLoopback.lock_count(); }
143 int signal_count() { return mt_loop_back_count(); }
144 bool InCriticalSection() { return SignalMTLoopback.InCriticalSection(); }
145};
146
147// This test will always succeed. However, if the default template instantiation
148// changes from single threaded to multi threaded it will break the build here.
149TEST_F(SigslotDefault, DefaultIsST) {
150 EXPECT_TRUE(TemplateIsST(this));
151 EXPECT_TRUE(TemplateIsST(&signal_));
152}
153
154// ST slot, ST signal
155TEST_F(SigslotSTSlotTest, STLoopbackTest) {
156 SignalSTLoopback();
157 EXPECT_EQ(1, st_loop_back_count());
158 EXPECT_EQ(0, mt_loop_back_count());
159}
160
161// ST slot, MT signal
162TEST_F(SigslotSTSlotTest, MTLoopbackTest) {
163 SignalMTLoopback();
164 EXPECT_EQ(1, mt_loop_back_count());
165 EXPECT_EQ(0, st_loop_back_count());
166}
167
168// ST slot, both ST and MT (separate) signal
169TEST_F(SigslotSTSlotTest, AllLoopbackTest) {
170 SignalSTLoopback();
171 SignalMTLoopback();
172 EXPECT_EQ(1, mt_loop_back_count());
173 EXPECT_EQ(1, st_loop_back_count());
174}
175
176TEST_F(SigslotSTSlotTest, Reconnect) {
177 SignalSTLoopback();
178 SignalMTLoopback();
179 EXPECT_EQ(1, mt_loop_back_count());
180 EXPECT_EQ(1, st_loop_back_count());
181 Disconnect();
182 SignalSTLoopback();
183 SignalMTLoopback();
184 EXPECT_EQ(1, mt_loop_back_count());
185 EXPECT_EQ(1, st_loop_back_count());
186 Connect();
187 SignalSTLoopback();
188 SignalMTLoopback();
189 EXPECT_EQ(2, mt_loop_back_count());
190 EXPECT_EQ(2, st_loop_back_count());
191}
192
193// MT slot, ST signal
194TEST_F(SigslotMTSlotTest, STLoopbackTest) {
195 SignalSTLoopback();
196 EXPECT_EQ(1, st_loop_back_count());
197 EXPECT_EQ(0, mt_loop_back_count());
198}
199
200// MT slot, MT signal
201TEST_F(SigslotMTSlotTest, MTLoopbackTest) {
202 SignalMTLoopback();
203 EXPECT_EQ(1, mt_loop_back_count());
204 EXPECT_EQ(0, st_loop_back_count());
205}
206
207// MT slot, both ST and MT (separate) signal
208TEST_F(SigslotMTSlotTest, AllLoopbackTest) {
209 SignalMTLoopback();
210 SignalSTLoopback();
211 EXPECT_EQ(1, st_loop_back_count());
212 EXPECT_EQ(1, mt_loop_back_count());
213}
214
215// Test that locks are acquired and released correctly.
216TEST_F(SigslotMTLockTest, LockSanity) {
217 const int lock_count = SignalLockCount();
218 Signal();
219 EXPECT_FALSE(InCriticalSection());
220 EXPECT_EQ(lock_count + 1, SignalLockCount());
221 EXPECT_EQ(1, signal_count());
222}
223
224// Destroy signal and slot in different orders.
225TEST(DestructionOrder, SignalFirst) {
226 sigslot::signal0<>* signal = new sigslot::signal0<>;
227 SigslotReceiver<>* receiver = new SigslotReceiver<>();
228 receiver->Connect(signal);
229 (*signal)();
230 EXPECT_EQ(1, receiver->signal_count());
231 delete signal;
232 delete receiver;
233}
234
235TEST(DestructionOrder, SlotFirst) {
236 sigslot::signal0<>* signal = new sigslot::signal0<>;
237 SigslotReceiver<>* receiver = new SigslotReceiver<>();
238 receiver->Connect(signal);
239 (*signal)();
240 EXPECT_EQ(1, receiver->signal_count());
241
242 delete receiver;
243 (*signal)();
244 delete signal;
245}