blob: a62e5479df269c5220cf1d9e3f74b540048ba540 [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
Yves Gerey3e707812018-11-28 16:47:49 +010011#include <string>
deadbeef08187d42017-02-25 11:21:18 -080012
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "rtc_base/bind.h"
Steve Anton10542f22019-01-11 09:11:00 -080014#include "rtc_base/ref_count.h"
15#include "rtc_base/ref_counted_object.h"
Yves Gerey3e707812018-11-28 16:47:49 +010016#include "test/gtest.h"
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020017
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000018namespace rtc {
19
20namespace {
21
Magnus Jedvertb2745472015-08-25 17:56:22 +020022struct LifeTimeCheck;
23
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000024struct MethodBindTester {
25 void NullaryVoid() { ++call_count; }
Yves Gerey665174f2018-06-19 15:03:05 +020026 int NullaryInt() {
27 ++call_count;
28 return 1;
29 }
30 int NullaryConst() const {
31 ++call_count;
32 return 2;
33 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000034 void UnaryVoid(int dummy) { ++call_count; }
Yves Gerey665174f2018-06-19 15:03:05 +020035 template <class T>
36 T Identity(T value) {
37 ++call_count;
38 return value;
39 }
noahric5d9b92b2015-10-24 11:14:46 -070040 int UnaryByPointer(int* value) const {
41 ++call_count;
42 return ++(*value);
43 }
44 int UnaryByRef(const int& value) const {
45 ++call_count;
46 return ++const_cast<int&>(value);
47 }
Yves Gerey665174f2018-06-19 15:03:05 +020048 int Multiply(int a, int b) const {
49 ++call_count;
50 return a * b;
51 }
Magnus Jedvertb2745472015-08-25 17:56:22 +020052 void RefArgument(const scoped_refptr<LifeTimeCheck>& object) {
53 EXPECT_TRUE(object.get() != nullptr);
54 }
55
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000056 mutable int call_count;
57};
58
Yves Gerey665174f2018-06-19 15:03:05 +020059struct A {
60 int dummy;
61};
62struct B : public RefCountInterface {
63 int dummy;
64};
65struct C : public A, B {};
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020066struct D {
67 int AddRef();
68};
Yves Gerey665174f2018-06-19 15:03:05 +020069struct E : public D {
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020070 int Release();
71};
72struct F {
73 void AddRef();
74 void Release();
75};
76
Magnus Jedvertb2745472015-08-25 17:56:22 +020077struct LifeTimeCheck {
78 LifeTimeCheck() : ref_count_(0) {}
79 void AddRef() { ++ref_count_; }
80 void Release() { --ref_count_; }
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020081 void NullaryVoid() {}
Magnus Jedvertb2745472015-08-25 17:56:22 +020082 int ref_count_;
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020083};
84
Yves Gerey665174f2018-06-19 15:03:05 +020085int Return42() {
86 return 42;
87}
88int Negate(int a) {
89 return -a;
90}
91int Multiply(int a, int b) {
92 return a * b;
93}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000094
95} // namespace
96
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020097// Try to catch any problem with scoped_refptr type deduction in rtc::Bind at
98// compile time.
99#define EXPECT_IS_CAPTURED_AS_PTR(T) \
100 static_assert(is_same<detail::PointerType<T>::type, T*>::value, \
Yves Gerey665174f2018-06-19 15:03:05 +0200101 "PointerTyp" \
102 "e")
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200103#define EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(T) \
104 static_assert( \
105 is_same<detail::PointerType<T>::type, scoped_refptr<T>>::value, \
106 "PointerType")
107
108EXPECT_IS_CAPTURED_AS_PTR(void);
109EXPECT_IS_CAPTURED_AS_PTR(int);
110EXPECT_IS_CAPTURED_AS_PTR(double);
111EXPECT_IS_CAPTURED_AS_PTR(A);
112EXPECT_IS_CAPTURED_AS_PTR(D);
113EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*);
deadbeefccaaffb2017-02-25 12:56:20 -0800114EXPECT_IS_CAPTURED_AS_PTR(
115 decltype(Unretained<RefCountedObject<RefCountInterface>>));
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200116
117EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface);
118EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B);
119EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(C);
120EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(E);
121EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(F);
122EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<RefCountInterface>);
123EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<B>);
124EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<C>);
Magnus Jedvert1b40a9a2015-10-12 15:50:43 +0200125EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(const RefCountedObject<RefCountInterface>);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200126
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000127TEST(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;
noahric5d9b92b2015-10-24 11:14:46 -0700146 // 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)());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000149 EXPECT_EQ(12, value);
150 EXPECT_EQ(7, object.call_count);
noahric5d9b92b2015-10-24 11:14:46 -0700151 // 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);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000157 EXPECT_EQ(8, object.call_count);
noahric5d9b92b2015-10-24 11:14:46 -0700158 EXPECT_EQ(56, Bind(&MethodBindTester::Multiply, &object, 7, 8)());
159 EXPECT_EQ(9, object.call_count);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000160}
161
162TEST(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
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200168// Test Bind where method object implements RefCountInterface and is passed as a
169// pointer.
170TEST(BindTest, CapturePointerAsScopedRefPtr) {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200171 LifeTimeCheck object;
172 EXPECT_EQ(object.ref_count_, 0);
173 scoped_refptr<LifeTimeCheck> scoped_object(&object);
174 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200175 {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200176 auto functor = Bind(&LifeTimeCheck::NullaryVoid, &object);
177 EXPECT_EQ(object.ref_count_, 2);
178 scoped_object = nullptr;
179 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200180 }
Magnus Jedvertb2745472015-08-25 17:56:22 +0200181 EXPECT_EQ(object.ref_count_, 0);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200182}
183
184// Test Bind where method object implements RefCountInterface and is passed as a
185// scoped_refptr<>.
186TEST(BindTest, CaptureScopedRefPtrAsScopedRefPtr) {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200187 LifeTimeCheck object;
188 EXPECT_EQ(object.ref_count_, 0);
189 scoped_refptr<LifeTimeCheck> scoped_object(&object);
190 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200191 {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200192 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);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200196 }
Magnus Jedvertb2745472015-08-25 17:56:22 +0200197 EXPECT_EQ(object.ref_count_, 0);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200198}
199
200// Test Bind where method object is captured as scoped_refptr<> and the functor
201// dies while there are references left.
202TEST(BindTest, FunctorReleasesObjectOnDestruction) {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200203 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.
214TEST(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
230namespace {
231
Yves Gerey665174f2018-06-19 15:03:05 +0200232const int* Ref(const int& a) {
233 return &a;
234}
Magnus Jedvertb2745472015-08-25 17:56:22 +0200235
236} // anonymous namespace
237
noahric5d9b92b2015-10-24 11:14:46 -0700238// Test Bind with non-scoped_refptr<> reference argument, which should be
239// modified to a non-reference capture.
Magnus Jedvertb2745472015-08-25 17:56:22 +0200240TEST(BindTest, RefArgument) {
241 const int x = 42;
noahric5d9b92b2015-10-24 11:14:46 -0700242 EXPECT_EQ(&x, Ref(x));
243 // Bind() should make a copy of |x|, i.e. the pointers should be different.
Magnus Jedvertb2745472015-08-25 17:56:22 +0200244 auto functor = Bind(&Ref, x);
noahric5d9b92b2015-10-24 11:14:46 -0700245 EXPECT_NE(&x, functor());
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200246}
247
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000248} // namespace rtc