blob: d38729d9df20b64eb06484d94ffbece584321ec0 [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; }
28 int UnaryByRef(int& value) const { ++call_count; return ++value; } // NOLINT
29 int Multiply(int a, int b) const { ++call_count; return a * b; }
Magnus Jedvertb2745472015-08-25 17:56:22 +020030 void RefArgument(const scoped_refptr<LifeTimeCheck>& object) {
31 EXPECT_TRUE(object.get() != nullptr);
32 }
33
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000034 mutable int call_count;
35};
36
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020037struct A { int dummy; };
38struct B: public RefCountInterface { int dummy; };
39struct C: public A, B {};
40struct D {
41 int AddRef();
42};
43struct E: public D {
44 int Release();
45};
46struct F {
47 void AddRef();
48 void Release();
49};
50
Magnus Jedvertb2745472015-08-25 17:56:22 +020051struct LifeTimeCheck {
52 LifeTimeCheck() : ref_count_(0) {}
53 void AddRef() { ++ref_count_; }
54 void Release() { --ref_count_; }
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020055 void NullaryVoid() {}
Magnus Jedvertb2745472015-08-25 17:56:22 +020056 int ref_count_;
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020057};
58
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059int Return42() { return 42; }
60int Negate(int a) { return -a; }
61int Multiply(int a, int b) { return a * b; }
62
63} // namespace
64
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020065// Try to catch any problem with scoped_refptr type deduction in rtc::Bind at
66// compile time.
Magnus Jedvertb2745472015-08-25 17:56:22 +020067static_assert(is_same<detail::RemoveScopedPtrRef<
68 const scoped_refptr<RefCountInterface>&>::type,
69 scoped_refptr<RefCountInterface>>::value,
70 "const scoped_refptr& should be captured by value");
71
72static_assert(is_same<detail::RemoveScopedPtrRef<const scoped_refptr<F>&>::type,
73 scoped_refptr<F>>::value,
74 "const scoped_refptr& should be captured by value");
75
76static_assert(
77 is_same<detail::RemoveScopedPtrRef<const int&>::type, const int&>::value,
78 "const int& should be captured as const int&");
79
80static_assert(
81 is_same<detail::RemoveScopedPtrRef<const F&>::type, const F&>::value,
82 "const F& should be captured as const F&");
83
84static_assert(
85 is_same<detail::RemoveScopedPtrRef<F&>::type, F&>::value,
86 "F& should be captured as F&");
87
Magnus Jedvertd3de9c52015-08-20 16:03:52 +020088#define EXPECT_IS_CAPTURED_AS_PTR(T) \
89 static_assert(is_same<detail::PointerType<T>::type, T*>::value, \
90 "PointerType")
91#define EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(T) \
92 static_assert( \
93 is_same<detail::PointerType<T>::type, scoped_refptr<T>>::value, \
94 "PointerType")
95
96EXPECT_IS_CAPTURED_AS_PTR(void);
97EXPECT_IS_CAPTURED_AS_PTR(int);
98EXPECT_IS_CAPTURED_AS_PTR(double);
99EXPECT_IS_CAPTURED_AS_PTR(A);
100EXPECT_IS_CAPTURED_AS_PTR(D);
101EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*);
102
103EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface);
104EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B);
105EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(C);
106EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(E);
107EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(F);
108EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<RefCountInterface>);
109EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<B>);
110EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<C>);
111
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000112TEST(BindTest, BindToMethod) {
113 MethodBindTester object = {0};
114 EXPECT_EQ(0, object.call_count);
115 Bind(&MethodBindTester::NullaryVoid, &object)();
116 EXPECT_EQ(1, object.call_count);
117 EXPECT_EQ(1, Bind(&MethodBindTester::NullaryInt, &object)());
118 EXPECT_EQ(2, object.call_count);
119 EXPECT_EQ(2, Bind(&MethodBindTester::NullaryConst,
120 static_cast<const MethodBindTester*>(&object))());
121 EXPECT_EQ(3, object.call_count);
122 Bind(&MethodBindTester::UnaryVoid, &object, 5)();
123 EXPECT_EQ(4, object.call_count);
124 EXPECT_EQ(100, Bind(&MethodBindTester::Identity<int>, &object, 100)());
125 EXPECT_EQ(5, object.call_count);
126 const std::string string_value("test string");
127 EXPECT_EQ(string_value, Bind(&MethodBindTester::Identity<std::string>,
128 &object, string_value)());
129 EXPECT_EQ(6, object.call_count);
130 int value = 11;
131 EXPECT_EQ(12, Bind(&MethodBindTester::UnaryByRef, &object, value)());
132 EXPECT_EQ(12, value);
133 EXPECT_EQ(7, object.call_count);
134 EXPECT_EQ(56, Bind(&MethodBindTester::Multiply, &object, 7, 8)());
135 EXPECT_EQ(8, object.call_count);
136}
137
138TEST(BindTest, BindToFunction) {
139 EXPECT_EQ(42, Bind(&Return42)());
140 EXPECT_EQ(3, Bind(&Negate, -3)());
141 EXPECT_EQ(56, Bind(&Multiply, 8, 7)());
142}
143
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200144// Test Bind where method object implements RefCountInterface and is passed as a
145// pointer.
146TEST(BindTest, CapturePointerAsScopedRefPtr) {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200147 LifeTimeCheck object;
148 EXPECT_EQ(object.ref_count_, 0);
149 scoped_refptr<LifeTimeCheck> scoped_object(&object);
150 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200151 {
Magnus Jedvertb2745472015-08-25 17:56:22 +0200152 auto functor = Bind(&LifeTimeCheck::NullaryVoid, &object);
153 EXPECT_EQ(object.ref_count_, 2);
154 scoped_object = nullptr;
155 EXPECT_EQ(object.ref_count_, 1);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200156 }
Magnus Jedvertb2745472015-08-25 17:56:22 +0200157 EXPECT_EQ(object.ref_count_, 0);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200158}
159
160// Test Bind where method object implements RefCountInterface and is passed as a
161// scoped_refptr<>.
162TEST(BindTest, CaptureScopedRefPtrAsScopedRefPtr) {
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, scoped_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 is captured as scoped_refptr<> and the functor
177// dies while there are references left.
178TEST(BindTest, FunctorReleasesObjectOnDestruction) {
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);
183 Bind(&LifeTimeCheck::NullaryVoid, &object)();
184 EXPECT_EQ(object.ref_count_, 1);
185 scoped_object = nullptr;
186 EXPECT_EQ(object.ref_count_, 0);
187}
188
189// Test Bind with scoped_refptr<> argument.
190TEST(BindTest, ScopedRefPointerArgument) {
191 LifeTimeCheck object;
192 EXPECT_EQ(object.ref_count_, 0);
193 scoped_refptr<LifeTimeCheck> scoped_object(&object);
194 EXPECT_EQ(object.ref_count_, 1);
195 {
196 MethodBindTester bind_tester;
197 auto functor =
198 Bind(&MethodBindTester::RefArgument, &bind_tester, scoped_object);
199 EXPECT_EQ(object.ref_count_, 2);
200 }
201 EXPECT_EQ(object.ref_count_, 1);
202 scoped_object = nullptr;
203 EXPECT_EQ(object.ref_count_, 0);
204}
205
206namespace {
207
208const int* Ref(const int& a) { return &a; }
209
210} // anonymous namespace
211
212// Test Bind with non-scoped_refptr<> reference argument.
213TEST(BindTest, RefArgument) {
214 const int x = 42;
215 EXPECT_TRUE(Ref(x) == &x);
216 // Bind() should not make a copy of |x|, i.e. the pointers should be the same.
217 auto functor = Bind(&Ref, x);
218 EXPECT_TRUE(functor() == &x);
Magnus Jedvertd3de9c52015-08-20 16:03:52 +0200219}
220
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000221} // namespace rtc