blob: ed0913fdd3d2e96838faac36f0175d5d1a28dde0 [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
deadbeef08187d42017-02-25 11:21:18 -080011#include <type_traits>
12
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020013#include "rtc_base/bind.h"
14#include "rtc_base/gunit.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000015
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020016#include "rtc_base/refcount.h"
Niels Möller84255bb2017-10-06 13:43:23 +020017#include "rtc_base/refcountedobject.h"
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020018
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000019namespace rtc {
20
21namespace {
22
Magnus Jedvertb2745472015-08-25 17:56:22 +020023struct LifeTimeCheck;
24
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000025struct MethodBindTester {
26 void NullaryVoid() { ++call_count; }
Yves Gerey665174f2018-06-19 15:03:05 +020027 int NullaryInt() {
28 ++call_count;
29 return 1;
30 }
31 int NullaryConst() const {
32 ++call_count;
33 return 2;
34 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000035 void UnaryVoid(int dummy) { ++call_count; }
Yves Gerey665174f2018-06-19 15:03:05 +020036 template <class T>
37 T Identity(T value) {
38 ++call_count;
39 return value;
40 }
noahric5d9b92b2015-10-24 11:14:46 -070041 int UnaryByPointer(int* value) const {
42 ++call_count;
43 return ++(*value);
44 }
45 int UnaryByRef(const int& value) const {
46 ++call_count;
47 return ++const_cast<int&>(value);
48 }
Yves Gerey665174f2018-06-19 15:03:05 +020049 int Multiply(int a, int b) const {
50 ++call_count;
51 return a * b;
52 }
Magnus Jedvertb2745472015-08-25 17:56:22 +020053 void RefArgument(const scoped_refptr<LifeTimeCheck>& object) {
54 EXPECT_TRUE(object.get() != nullptr);
55 }
56
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000057 mutable int call_count;
58};
59
Yves Gerey665174f2018-06-19 15:03:05 +020060struct A {
61 int dummy;
62};
63struct B : public RefCountInterface {
64 int dummy;
65};
66struct C : public A, B {};
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020067struct D {
68 int AddRef();
69};
Yves Gerey665174f2018-06-19 15:03:05 +020070struct E : public D {
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020071 int Release();
72};
73struct F {
74 void AddRef();
75 void Release();
76};
77
Magnus Jedvertb2745472015-08-25 17:56:22 +020078struct LifeTimeCheck {
79 LifeTimeCheck() : ref_count_(0) {}
80 void AddRef() { ++ref_count_; }
81 void Release() { --ref_count_; }
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020082 void NullaryVoid() {}
Magnus Jedvertb2745472015-08-25 17:56:22 +020083 int ref_count_;
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020084};
85
Yves Gerey665174f2018-06-19 15:03:05 +020086int Return42() {
87 return 42;
88}
89int Negate(int a) {
90 return -a;
91}
92int Multiply(int a, int b) {
93 return a * b;
94}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000095
96} // namespace
97
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020098// 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(is_same<detail::PointerType<T>::type, T*>::value, \
Yves Gerey665174f2018-06-19 15:03:05 +0200102 "PointerTyp" \
103 "e")
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200104#define EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(T) \
105 static_assert( \
106 is_same<detail::PointerType<T>::type, scoped_refptr<T>>::value, \
107 "PointerType")
108
109EXPECT_IS_CAPTURED_AS_PTR(void);
110EXPECT_IS_CAPTURED_AS_PTR(int);
111EXPECT_IS_CAPTURED_AS_PTR(double);
112EXPECT_IS_CAPTURED_AS_PTR(A);
113EXPECT_IS_CAPTURED_AS_PTR(D);
114EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*);
deadbeefccaaffb2017-02-25 12:56:20 -0800115EXPECT_IS_CAPTURED_AS_PTR(
116 decltype(Unretained<RefCountedObject<RefCountInterface>>));
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200117
118EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface);
119EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B);
120EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(C);
121EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(E);
122EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(F);
123EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<RefCountInterface>);
124EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<B>);
125EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<C>);
Magnus Jedvert1b40a9a2015-10-12 15:50:43 +0200126EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(const RefCountedObject<RefCountInterface>);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200127
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000128TEST(BindTest, BindToMethod) {
129 MethodBindTester object = {0};
130 EXPECT_EQ(0, object.call_count);
131 Bind(&MethodBindTester::NullaryVoid, &object)();
132 EXPECT_EQ(1, object.call_count);
133 EXPECT_EQ(1, Bind(&MethodBindTester::NullaryInt, &object)());
134 EXPECT_EQ(2, object.call_count);
135 EXPECT_EQ(2, Bind(&MethodBindTester::NullaryConst,
136 static_cast<const MethodBindTester*>(&object))());
137 EXPECT_EQ(3, object.call_count);
138 Bind(&MethodBindTester::UnaryVoid, &object, 5)();
139 EXPECT_EQ(4, object.call_count);
140 EXPECT_EQ(100, Bind(&MethodBindTester::Identity<int>, &object, 100)());
141 EXPECT_EQ(5, object.call_count);
142 const std::string string_value("test string");
143 EXPECT_EQ(string_value, Bind(&MethodBindTester::Identity<std::string>,
144 &object, string_value)());
145 EXPECT_EQ(6, object.call_count);
146 int value = 11;
noahric5d9b92b2015-10-24 11:14:46 -0700147 // Bind binds by value, even if the method signature is by reference, so
148 // "reference" binds require pointers.
149 EXPECT_EQ(12, Bind(&MethodBindTester::UnaryByPointer, &object, &value)());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000150 EXPECT_EQ(12, value);
151 EXPECT_EQ(7, object.call_count);
noahric5d9b92b2015-10-24 11:14:46 -0700152 // It's possible to bind to a function that takes a const reference, though
153 // the capture will be a copy. See UnaryByRef hackery above where it removes
154 // the const to make sure the underlying storage is, in fact, a copy.
155 EXPECT_EQ(13, Bind(&MethodBindTester::UnaryByRef, &object, value)());
156 // But the original value is unmodified.
157 EXPECT_EQ(12, value);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000158 EXPECT_EQ(8, object.call_count);
noahric5d9b92b2015-10-24 11:14:46 -0700159 EXPECT_EQ(56, Bind(&MethodBindTester::Multiply, &object, 7, 8)());
160 EXPECT_EQ(9, object.call_count);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000161}
162
163TEST(BindTest, BindToFunction) {
164 EXPECT_EQ(42, Bind(&Return42)());
165 EXPECT_EQ(3, Bind(&Negate, -3)());
166 EXPECT_EQ(56, Bind(&Multiply, 8, 7)());
167}
168
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200169// Test Bind where method object implements RefCountInterface and is passed as a
170// pointer.
171TEST(BindTest, CapturePointerAsScopedRefPtr) {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200172 LifeTimeCheck object;
173 EXPECT_EQ(object.ref_count_, 0);
174 scoped_refptr<LifeTimeCheck> scoped_object(&object);
175 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200176 {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200177 auto functor = Bind(&LifeTimeCheck::NullaryVoid, &object);
178 EXPECT_EQ(object.ref_count_, 2);
179 scoped_object = nullptr;
180 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200181 }
Magnus Jedvertb2745472015-08-25 17:56:22 +0200182 EXPECT_EQ(object.ref_count_, 0);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200183}
184
185// Test Bind where method object implements RefCountInterface and is passed as a
186// scoped_refptr<>.
187TEST(BindTest, CaptureScopedRefPtrAsScopedRefPtr) {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200188 LifeTimeCheck object;
189 EXPECT_EQ(object.ref_count_, 0);
190 scoped_refptr<LifeTimeCheck> scoped_object(&object);
191 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200192 {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200193 auto functor = Bind(&LifeTimeCheck::NullaryVoid, scoped_object);
194 EXPECT_EQ(object.ref_count_, 2);
195 scoped_object = nullptr;
196 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200197 }
Magnus Jedvertb2745472015-08-25 17:56:22 +0200198 EXPECT_EQ(object.ref_count_, 0);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200199}
200
201// Test Bind where method object is captured as scoped_refptr<> and the functor
202// dies while there are references left.
203TEST(BindTest, FunctorReleasesObjectOnDestruction) {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200204 LifeTimeCheck object;
205 EXPECT_EQ(object.ref_count_, 0);
206 scoped_refptr<LifeTimeCheck> scoped_object(&object);
207 EXPECT_EQ(object.ref_count_, 1);
208 Bind(&LifeTimeCheck::NullaryVoid, &object)();
209 EXPECT_EQ(object.ref_count_, 1);
210 scoped_object = nullptr;
211 EXPECT_EQ(object.ref_count_, 0);
212}
213
214// Test Bind with scoped_refptr<> argument.
215TEST(BindTest, ScopedRefPointerArgument) {
216 LifeTimeCheck object;
217 EXPECT_EQ(object.ref_count_, 0);
218 scoped_refptr<LifeTimeCheck> scoped_object(&object);
219 EXPECT_EQ(object.ref_count_, 1);
220 {
221 MethodBindTester bind_tester;
222 auto functor =
223 Bind(&MethodBindTester::RefArgument, &bind_tester, scoped_object);
224 EXPECT_EQ(object.ref_count_, 2);
225 }
226 EXPECT_EQ(object.ref_count_, 1);
227 scoped_object = nullptr;
228 EXPECT_EQ(object.ref_count_, 0);
229}
230
231namespace {
232
Yves Gerey665174f2018-06-19 15:03:05 +0200233const int* Ref(const int& a) {
234 return &a;
235}
Magnus Jedvertb2745472015-08-25 17:56:22 +0200236
237} // anonymous namespace
238
noahric5d9b92b2015-10-24 11:14:46 -0700239// Test Bind with non-scoped_refptr<> reference argument, which should be
240// modified to a non-reference capture.
Magnus Jedvertb2745472015-08-25 17:56:22 +0200241TEST(BindTest, RefArgument) {
242 const int x = 42;
noahric5d9b92b2015-10-24 11:14:46 -0700243 EXPECT_EQ(&x, Ref(x));
244 // Bind() should make a copy of |x|, i.e. the pointers should be different.
Magnus Jedvertb2745472015-08-25 17:56:22 +0200245 auto functor = Bind(&Ref, x);
noahric5d9b92b2015-10-24 11:14:46 -0700246 EXPECT_NE(&x, functor());
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200247}
248
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000249} // namespace rtc