blob: be8d79cb6af25cfd62948d7eb4852a41045276ee [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
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 "webrtc/base/bind.h"
12#include "webrtc/base/gunit.h"
13
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020014#include "webrtc/base/refcount.h"
15
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000016namespace rtc {
17
18namespace {
19
Magnus Jedvertb2745472015-08-25 17:56:22 +020020struct LifeTimeCheck;
21
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000022struct MethodBindTester {
23 void NullaryVoid() { ++call_count; }
24 int NullaryInt() { ++call_count; return 1; }
25 int NullaryConst() const { ++call_count; return 2; }
26 void UnaryVoid(int dummy) { ++call_count; }
27 template <class T> T Identity(T value) { ++call_count; return value; }
noahric5d9b92b2015-10-24 11:14:46 -070028 int UnaryByPointer(int* value) const {
29 ++call_count;
30 return ++(*value);
31 }
32 int UnaryByRef(const int& value) const {
33 ++call_count;
34 return ++const_cast<int&>(value);
35 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000036 int Multiply(int a, int b) const { ++call_count; return a * b; }
Magnus Jedvertb2745472015-08-25 17:56:22 +020037 void RefArgument(const scoped_refptr<LifeTimeCheck>& object) {
38 EXPECT_TRUE(object.get() != nullptr);
39 }
40
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000041 mutable int call_count;
42};
43
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020044struct A { int dummy; };
45struct B: public RefCountInterface { int dummy; };
46struct C: public A, B {};
47struct D {
48 int AddRef();
49};
50struct E: public D {
51 int Release();
52};
53struct F {
54 void AddRef();
55 void Release();
56};
57
Magnus Jedvertb2745472015-08-25 17:56:22 +020058struct LifeTimeCheck {
59 LifeTimeCheck() : ref_count_(0) {}
60 void AddRef() { ++ref_count_; }
61 void Release() { --ref_count_; }
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020062 void NullaryVoid() {}
Magnus Jedvertb2745472015-08-25 17:56:22 +020063 int ref_count_;
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020064};
65
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000066int Return42() { return 42; }
67int Negate(int a) { return -a; }
68int Multiply(int a, int b) { return a * b; }
69
70} // namespace
71
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020072// Try to catch any problem with scoped_refptr type deduction in rtc::Bind at
73// compile time.
noahric5d9b92b2015-10-24 11:14:46 -070074static_assert(
75 is_same<
76 rtc::remove_reference<const scoped_refptr<RefCountInterface>&>::type,
77 const scoped_refptr<RefCountInterface>>::value,
78 "const scoped_refptr& should be captured by value");
Magnus Jedvertb2745472015-08-25 17:56:22 +020079
noahric5d9b92b2015-10-24 11:14:46 -070080static_assert(is_same<rtc::remove_reference<const scoped_refptr<F>&>::type,
81 const scoped_refptr<F>>::value,
Magnus Jedvertb2745472015-08-25 17:56:22 +020082 "const scoped_refptr& should be captured by value");
83
84static_assert(
noahric5d9b92b2015-10-24 11:14:46 -070085 is_same<rtc::remove_reference<const int&>::type, const int>::value,
86 "const int& should be captured as const int");
Magnus Jedvertb2745472015-08-25 17:56:22 +020087
noahric5d9b92b2015-10-24 11:14:46 -070088static_assert(is_same<rtc::remove_reference<const F&>::type, const F>::value,
89 "const F& should be captured as const F");
Magnus Jedvertb2745472015-08-25 17:56:22 +020090
noahric5d9b92b2015-10-24 11:14:46 -070091static_assert(is_same<rtc::remove_reference<F&>::type, F>::value,
92 "F& should be captured as F");
Magnus Jedvertb2745472015-08-25 17:56:22 +020093
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020094#define EXPECT_IS_CAPTURED_AS_PTR(T) \
95 static_assert(is_same<detail::PointerType<T>::type, T*>::value, \
96 "PointerType")
97#define EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(T) \
98 static_assert( \
99 is_same<detail::PointerType<T>::type, scoped_refptr<T>>::value, \
100 "PointerType")
101
102EXPECT_IS_CAPTURED_AS_PTR(void);
103EXPECT_IS_CAPTURED_AS_PTR(int);
104EXPECT_IS_CAPTURED_AS_PTR(double);
105EXPECT_IS_CAPTURED_AS_PTR(A);
106EXPECT_IS_CAPTURED_AS_PTR(D);
107EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*);
108
109EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface);
110EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B);
111EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(C);
112EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(E);
113EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(F);
114EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<RefCountInterface>);
115EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<B>);
116EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<C>);
Magnus Jedvert1b40a9a2015-10-12 15:50:43 +0200117EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(const RefCountedObject<RefCountInterface>);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200118
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000119TEST(BindTest, BindToMethod) {
120 MethodBindTester object = {0};
121 EXPECT_EQ(0, object.call_count);
122 Bind(&MethodBindTester::NullaryVoid, &object)();
123 EXPECT_EQ(1, object.call_count);
124 EXPECT_EQ(1, Bind(&MethodBindTester::NullaryInt, &object)());
125 EXPECT_EQ(2, object.call_count);
126 EXPECT_EQ(2, Bind(&MethodBindTester::NullaryConst,
127 static_cast<const MethodBindTester*>(&object))());
128 EXPECT_EQ(3, object.call_count);
129 Bind(&MethodBindTester::UnaryVoid, &object, 5)();
130 EXPECT_EQ(4, object.call_count);
131 EXPECT_EQ(100, Bind(&MethodBindTester::Identity<int>, &object, 100)());
132 EXPECT_EQ(5, object.call_count);
133 const std::string string_value("test string");
134 EXPECT_EQ(string_value, Bind(&MethodBindTester::Identity<std::string>,
135 &object, string_value)());
136 EXPECT_EQ(6, object.call_count);
137 int value = 11;
noahric5d9b92b2015-10-24 11:14:46 -0700138 // Bind binds by value, even if the method signature is by reference, so
139 // "reference" binds require pointers.
140 EXPECT_EQ(12, Bind(&MethodBindTester::UnaryByPointer, &object, &value)());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000141 EXPECT_EQ(12, value);
142 EXPECT_EQ(7, object.call_count);
noahric5d9b92b2015-10-24 11:14:46 -0700143 // It's possible to bind to a function that takes a const reference, though
144 // the capture will be a copy. See UnaryByRef hackery above where it removes
145 // the const to make sure the underlying storage is, in fact, a copy.
146 EXPECT_EQ(13, Bind(&MethodBindTester::UnaryByRef, &object, value)());
147 // But the original value is unmodified.
148 EXPECT_EQ(12, value);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000149 EXPECT_EQ(8, object.call_count);
noahric5d9b92b2015-10-24 11:14:46 -0700150 EXPECT_EQ(56, Bind(&MethodBindTester::Multiply, &object, 7, 8)());
151 EXPECT_EQ(9, object.call_count);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000152}
153
154TEST(BindTest, BindToFunction) {
155 EXPECT_EQ(42, Bind(&Return42)());
156 EXPECT_EQ(3, Bind(&Negate, -3)());
157 EXPECT_EQ(56, Bind(&Multiply, 8, 7)());
158}
159
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200160// Test Bind where method object implements RefCountInterface and is passed as a
161// pointer.
162TEST(BindTest, CapturePointerAsScopedRefPtr) {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200163 LifeTimeCheck object;
164 EXPECT_EQ(object.ref_count_, 0);
165 scoped_refptr<LifeTimeCheck> scoped_object(&object);
166 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200167 {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200168 auto functor = Bind(&LifeTimeCheck::NullaryVoid, &object);
169 EXPECT_EQ(object.ref_count_, 2);
170 scoped_object = nullptr;
171 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200172 }
Magnus Jedvertb2745472015-08-25 17:56:22 +0200173 EXPECT_EQ(object.ref_count_, 0);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200174}
175
176// Test Bind where method object implements RefCountInterface and is passed as a
177// scoped_refptr<>.
178TEST(BindTest, CaptureScopedRefPtrAsScopedRefPtr) {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200179 LifeTimeCheck object;
180 EXPECT_EQ(object.ref_count_, 0);
181 scoped_refptr<LifeTimeCheck> scoped_object(&object);
182 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200183 {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200184 auto functor = Bind(&LifeTimeCheck::NullaryVoid, scoped_object);
185 EXPECT_EQ(object.ref_count_, 2);
186 scoped_object = nullptr;
187 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200188 }
Magnus Jedvertb2745472015-08-25 17:56:22 +0200189 EXPECT_EQ(object.ref_count_, 0);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200190}
191
192// Test Bind where method object is captured as scoped_refptr<> and the functor
193// dies while there are references left.
194TEST(BindTest, FunctorReleasesObjectOnDestruction) {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200195 LifeTimeCheck object;
196 EXPECT_EQ(object.ref_count_, 0);
197 scoped_refptr<LifeTimeCheck> scoped_object(&object);
198 EXPECT_EQ(object.ref_count_, 1);
199 Bind(&LifeTimeCheck::NullaryVoid, &object)();
200 EXPECT_EQ(object.ref_count_, 1);
201 scoped_object = nullptr;
202 EXPECT_EQ(object.ref_count_, 0);
203}
204
205// Test Bind with scoped_refptr<> argument.
206TEST(BindTest, ScopedRefPointerArgument) {
207 LifeTimeCheck object;
208 EXPECT_EQ(object.ref_count_, 0);
209 scoped_refptr<LifeTimeCheck> scoped_object(&object);
210 EXPECT_EQ(object.ref_count_, 1);
211 {
212 MethodBindTester bind_tester;
213 auto functor =
214 Bind(&MethodBindTester::RefArgument, &bind_tester, scoped_object);
215 EXPECT_EQ(object.ref_count_, 2);
216 }
217 EXPECT_EQ(object.ref_count_, 1);
218 scoped_object = nullptr;
219 EXPECT_EQ(object.ref_count_, 0);
220}
221
222namespace {
223
224const int* Ref(const int& a) { return &a; }
225
226} // anonymous namespace
227
noahric5d9b92b2015-10-24 11:14:46 -0700228// Test Bind with non-scoped_refptr<> reference argument, which should be
229// modified to a non-reference capture.
Magnus Jedvertb2745472015-08-25 17:56:22 +0200230TEST(BindTest, RefArgument) {
231 const int x = 42;
noahric5d9b92b2015-10-24 11:14:46 -0700232 EXPECT_EQ(&x, Ref(x));
233 // Bind() should make a copy of |x|, i.e. the pointers should be different.
Magnus Jedvertb2745472015-08-25 17:56:22 +0200234 auto functor = Bind(&Ref, x);
noahric5d9b92b2015-10-24 11:14:46 -0700235 EXPECT_NE(&x, functor());
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200236}
237
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000238} // namespace rtc