1 /*
2 * Copyright 2004 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 "rtc_base/bind.h"
12
13 #include <string>
14
15 #include "rtc_base/ref_count.h"
16 #include "rtc_base/ref_counted_object.h"
17 #include "test/gtest.h"
18
19 namespace rtc {
20
21 namespace {
22
23 struct LifeTimeCheck;
24
25 struct MethodBindTester {
NullaryVoidrtc::__anon926602950111::MethodBindTester26 void NullaryVoid() { ++call_count; }
NullaryIntrtc::__anon926602950111::MethodBindTester27 int NullaryInt() {
28 ++call_count;
29 return 1;
30 }
NullaryConstrtc::__anon926602950111::MethodBindTester31 int NullaryConst() const {
32 ++call_count;
33 return 2;
34 }
UnaryVoidrtc::__anon926602950111::MethodBindTester35 void UnaryVoid(int dummy) { ++call_count; }
36 template <class T>
Identityrtc::__anon926602950111::MethodBindTester37 T Identity(T value) {
38 ++call_count;
39 return value;
40 }
UnaryByPointerrtc::__anon926602950111::MethodBindTester41 int UnaryByPointer(int* value) const {
42 ++call_count;
43 return ++(*value);
44 }
UnaryByRefrtc::__anon926602950111::MethodBindTester45 int UnaryByRef(const int& value) const {
46 ++call_count;
47 return ++const_cast<int&>(value);
48 }
Multiplyrtc::__anon926602950111::MethodBindTester49 int Multiply(int a, int b) const {
50 ++call_count;
51 return a * b;
52 }
RefArgumentrtc::__anon926602950111::MethodBindTester53 void RefArgument(const scoped_refptr<LifeTimeCheck>& object) {
54 EXPECT_TRUE(object.get() != nullptr);
55 }
56
57 mutable int call_count;
58 };
59
60 struct A {
61 int dummy;
62 };
63 struct B : public RefCountInterface {
64 int dummy;
65 };
66 struct C : public A, B {};
67 struct D {
68 int AddRef();
69 };
70 struct E : public D {
71 int Release();
72 };
73 struct F {
74 void AddRef();
75 void Release();
76 };
77
78 struct LifeTimeCheck {
LifeTimeCheckrtc::__anon926602950111::LifeTimeCheck79 LifeTimeCheck() : ref_count_(0) {}
AddRefrtc::__anon926602950111::LifeTimeCheck80 void AddRef() { ++ref_count_; }
Releasertc::__anon926602950111::LifeTimeCheck81 void Release() { --ref_count_; }
NullaryVoidrtc::__anon926602950111::LifeTimeCheck82 void NullaryVoid() {}
83 int ref_count_;
84 };
85
Return42()86 int Return42() {
87 return 42;
88 }
Negate(int a)89 int Negate(int a) {
90 return -a;
91 }
Multiply(int a,int b)92 int Multiply(int a, int b) {
93 return a * b;
94 }
95
96 } // namespace
97
98 // Try to catch any problem with scoped_refptr type deduction in rtc::Bind at
99 // compile time.
100 #define EXPECT_IS_CAPTURED_AS_PTR(T) \
101 static_assert(std::is_same<detail::PointerType<T>::type, T*>::value, \
102 "PointerType")
103 #define EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(T) \
104 static_assert( \
105 std::is_same<detail::PointerType<T>::type, scoped_refptr<T>>::value, \
106 "PointerType")
107
108 EXPECT_IS_CAPTURED_AS_PTR(void);
109 EXPECT_IS_CAPTURED_AS_PTR(int);
110 EXPECT_IS_CAPTURED_AS_PTR(double);
111 EXPECT_IS_CAPTURED_AS_PTR(A);
112 EXPECT_IS_CAPTURED_AS_PTR(D);
113 EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*);
114 EXPECT_IS_CAPTURED_AS_PTR(
115 decltype(Unretained<RefCountedObject<RefCountInterface>>));
116
117 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface);
118 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B);
119 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(C);
120 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(E);
121 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(F);
122 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<RefCountInterface>);
123 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<B>);
124 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<C>);
125 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(const RefCountedObject<RefCountInterface>);
126
TEST(BindTest,BindToMethod)127 TEST(BindTest, BindToMethod) {
128 MethodBindTester object = {0};
129 EXPECT_EQ(0, object.call_count);
130 Bind(&MethodBindTester::NullaryVoid, &object)();
131 EXPECT_EQ(1, object.call_count);
132 EXPECT_EQ(1, Bind(&MethodBindTester::NullaryInt, &object)());
133 EXPECT_EQ(2, object.call_count);
134 EXPECT_EQ(2, Bind(&MethodBindTester::NullaryConst,
135 static_cast<const MethodBindTester*>(&object))());
136 EXPECT_EQ(3, object.call_count);
137 Bind(&MethodBindTester::UnaryVoid, &object, 5)();
138 EXPECT_EQ(4, object.call_count);
139 EXPECT_EQ(100, Bind(&MethodBindTester::Identity<int>, &object, 100)());
140 EXPECT_EQ(5, object.call_count);
141 const std::string string_value("test string");
142 EXPECT_EQ(string_value, Bind(&MethodBindTester::Identity<std::string>,
143 &object, string_value)());
144 EXPECT_EQ(6, object.call_count);
145 int value = 11;
146 // Bind binds by value, even if the method signature is by reference, so
147 // "reference" binds require pointers.
148 EXPECT_EQ(12, Bind(&MethodBindTester::UnaryByPointer, &object, &value)());
149 EXPECT_EQ(12, value);
150 EXPECT_EQ(7, object.call_count);
151 // It's possible to bind to a function that takes a const reference, though
152 // the capture will be a copy. See UnaryByRef hackery above where it removes
153 // the const to make sure the underlying storage is, in fact, a copy.
154 EXPECT_EQ(13, Bind(&MethodBindTester::UnaryByRef, &object, value)());
155 // But the original value is unmodified.
156 EXPECT_EQ(12, value);
157 EXPECT_EQ(8, object.call_count);
158 EXPECT_EQ(56, Bind(&MethodBindTester::Multiply, &object, 7, 8)());
159 EXPECT_EQ(9, object.call_count);
160 }
161
TEST(BindTest,BindToFunction)162 TEST(BindTest, BindToFunction) {
163 EXPECT_EQ(42, Bind(&Return42)());
164 EXPECT_EQ(3, Bind(&Negate, -3)());
165 EXPECT_EQ(56, Bind(&Multiply, 8, 7)());
166 }
167
168 // Test Bind where method object implements RefCountInterface and is passed as a
169 // pointer.
TEST(BindTest,CapturePointerAsScopedRefPtr)170 TEST(BindTest, CapturePointerAsScopedRefPtr) {
171 LifeTimeCheck object;
172 EXPECT_EQ(object.ref_count_, 0);
173 scoped_refptr<LifeTimeCheck> scoped_object(&object);
174 EXPECT_EQ(object.ref_count_, 1);
175 {
176 auto functor = Bind(&LifeTimeCheck::NullaryVoid, &object);
177 EXPECT_EQ(object.ref_count_, 2);
178 scoped_object = nullptr;
179 EXPECT_EQ(object.ref_count_, 1);
180 }
181 EXPECT_EQ(object.ref_count_, 0);
182 }
183
184 // Test Bind where method object implements RefCountInterface and is passed as a
185 // scoped_refptr<>.
TEST(BindTest,CaptureScopedRefPtrAsScopedRefPtr)186 TEST(BindTest, CaptureScopedRefPtrAsScopedRefPtr) {
187 LifeTimeCheck object;
188 EXPECT_EQ(object.ref_count_, 0);
189 scoped_refptr<LifeTimeCheck> scoped_object(&object);
190 EXPECT_EQ(object.ref_count_, 1);
191 {
192 auto functor = Bind(&LifeTimeCheck::NullaryVoid, scoped_object);
193 EXPECT_EQ(object.ref_count_, 2);
194 scoped_object = nullptr;
195 EXPECT_EQ(object.ref_count_, 1);
196 }
197 EXPECT_EQ(object.ref_count_, 0);
198 }
199
200 // Test Bind where method object is captured as scoped_refptr<> and the functor
201 // dies while there are references left.
TEST(BindTest,FunctorReleasesObjectOnDestruction)202 TEST(BindTest, FunctorReleasesObjectOnDestruction) {
203 LifeTimeCheck object;
204 EXPECT_EQ(object.ref_count_, 0);
205 scoped_refptr<LifeTimeCheck> scoped_object(&object);
206 EXPECT_EQ(object.ref_count_, 1);
207 Bind(&LifeTimeCheck::NullaryVoid, &object)();
208 EXPECT_EQ(object.ref_count_, 1);
209 scoped_object = nullptr;
210 EXPECT_EQ(object.ref_count_, 0);
211 }
212
213 // Test Bind with scoped_refptr<> argument.
TEST(BindTest,ScopedRefPointerArgument)214 TEST(BindTest, ScopedRefPointerArgument) {
215 LifeTimeCheck object;
216 EXPECT_EQ(object.ref_count_, 0);
217 scoped_refptr<LifeTimeCheck> scoped_object(&object);
218 EXPECT_EQ(object.ref_count_, 1);
219 {
220 MethodBindTester bind_tester;
221 auto functor =
222 Bind(&MethodBindTester::RefArgument, &bind_tester, scoped_object);
223 EXPECT_EQ(object.ref_count_, 2);
224 }
225 EXPECT_EQ(object.ref_count_, 1);
226 scoped_object = nullptr;
227 EXPECT_EQ(object.ref_count_, 0);
228 }
229
230 namespace {
231
Ref(const int & a)232 const int* Ref(const int& a) {
233 return &a;
234 }
235
236 } // anonymous namespace
237
238 // Test Bind with non-scoped_refptr<> reference argument, which should be
239 // modified to a non-reference capture.
TEST(BindTest,RefArgument)240 TEST(BindTest, RefArgument) {
241 const int x = 42;
242 EXPECT_EQ(&x, Ref(x));
243 // Bind() should make a copy of |x|, i.e. the pointers should be different.
244 auto functor = Bind(&Ref, x);
245 EXPECT_NE(&x, functor());
246 }
247
248 } // namespace rtc
249