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 "webrtc/base/bind.h"
12 #include "webrtc/base/gunit.h"
13 
14 #include "webrtc/base/refcount.h"
15 
16 namespace rtc {
17 
18 namespace {
19 
20 struct LifeTimeCheck;
21 
22 struct MethodBindTester {
NullaryVoidrtc::__anon556b1bb70111::MethodBindTester23   void NullaryVoid() { ++call_count; }
NullaryIntrtc::__anon556b1bb70111::MethodBindTester24   int NullaryInt() { ++call_count; return 1; }
NullaryConstrtc::__anon556b1bb70111::MethodBindTester25   int NullaryConst() const { ++call_count; return 2; }
UnaryVoidrtc::__anon556b1bb70111::MethodBindTester26   void UnaryVoid(int dummy) { ++call_count; }
Identityrtc::__anon556b1bb70111::MethodBindTester27   template <class T> T Identity(T value) { ++call_count; return value; }
UnaryByPointerrtc::__anon556b1bb70111::MethodBindTester28   int UnaryByPointer(int* value) const {
29     ++call_count;
30     return ++(*value);
31   }
UnaryByRefrtc::__anon556b1bb70111::MethodBindTester32   int UnaryByRef(const int& value) const {
33     ++call_count;
34     return ++const_cast<int&>(value);
35   }
Multiplyrtc::__anon556b1bb70111::MethodBindTester36   int Multiply(int a, int b) const { ++call_count; return a * b; }
RefArgumentrtc::__anon556b1bb70111::MethodBindTester37   void RefArgument(const scoped_refptr<LifeTimeCheck>& object) {
38     EXPECT_TRUE(object.get() != nullptr);
39   }
40 
41   mutable int call_count;
42 };
43 
44 struct A { int dummy; };
45 struct B: public RefCountInterface { int dummy; };
46 struct C: public A, B {};
47 struct D {
48   int AddRef();
49 };
50 struct E: public D {
51   int Release();
52 };
53 struct F {
54   void AddRef();
55   void Release();
56 };
57 
58 struct LifeTimeCheck {
LifeTimeCheckrtc::__anon556b1bb70111::LifeTimeCheck59   LifeTimeCheck() : ref_count_(0) {}
AddRefrtc::__anon556b1bb70111::LifeTimeCheck60   void AddRef() { ++ref_count_; }
Releasertc::__anon556b1bb70111::LifeTimeCheck61   void Release() { --ref_count_; }
NullaryVoidrtc::__anon556b1bb70111::LifeTimeCheck62   void NullaryVoid() {}
63   int ref_count_;
64 };
65 
Return42()66 int Return42() { return 42; }
Negate(int a)67 int Negate(int a) { return -a; }
Multiply(int a,int b)68 int Multiply(int a, int b) { return a * b; }
69 
70 }  // namespace
71 
72 // Try to catch any problem with scoped_refptr type deduction in rtc::Bind at
73 // compile time.
74 static_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");
79 
80 static_assert(is_same<rtc::remove_reference<const scoped_refptr<F>&>::type,
81                       const scoped_refptr<F>>::value,
82               "const scoped_refptr& should be captured by value");
83 
84 static_assert(
85     is_same<rtc::remove_reference<const int&>::type, const int>::value,
86     "const int& should be captured as const int");
87 
88 static_assert(is_same<rtc::remove_reference<const F&>::type, const F>::value,
89               "const F& should be captured as const F");
90 
91 static_assert(is_same<rtc::remove_reference<F&>::type, F>::value,
92               "F& should be captured as F");
93 
94 #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 
102 EXPECT_IS_CAPTURED_AS_PTR(void);
103 EXPECT_IS_CAPTURED_AS_PTR(int);
104 EXPECT_IS_CAPTURED_AS_PTR(double);
105 EXPECT_IS_CAPTURED_AS_PTR(A);
106 EXPECT_IS_CAPTURED_AS_PTR(D);
107 EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*);
108 
109 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface);
110 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B);
111 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(C);
112 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(E);
113 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(F);
114 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<RefCountInterface>);
115 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<B>);
116 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<C>);
117 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(const RefCountedObject<RefCountInterface>);
118 
TEST(BindTest,BindToMethod)119 TEST(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;
138   // 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)());
141   EXPECT_EQ(12, value);
142   EXPECT_EQ(7, object.call_count);
143   // 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);
149   EXPECT_EQ(8, object.call_count);
150   EXPECT_EQ(56, Bind(&MethodBindTester::Multiply, &object, 7, 8)());
151   EXPECT_EQ(9, object.call_count);
152 }
153 
TEST(BindTest,BindToFunction)154 TEST(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 
160 // Test Bind where method object implements RefCountInterface and is passed as a
161 // pointer.
TEST(BindTest,CapturePointerAsScopedRefPtr)162 TEST(BindTest, CapturePointerAsScopedRefPtr) {
163   LifeTimeCheck object;
164   EXPECT_EQ(object.ref_count_, 0);
165   scoped_refptr<LifeTimeCheck> scoped_object(&object);
166   EXPECT_EQ(object.ref_count_, 1);
167   {
168     auto functor = Bind(&LifeTimeCheck::NullaryVoid, &object);
169     EXPECT_EQ(object.ref_count_, 2);
170     scoped_object = nullptr;
171     EXPECT_EQ(object.ref_count_, 1);
172   }
173   EXPECT_EQ(object.ref_count_, 0);
174 }
175 
176 // Test Bind where method object implements RefCountInterface and is passed as a
177 // scoped_refptr<>.
TEST(BindTest,CaptureScopedRefPtrAsScopedRefPtr)178 TEST(BindTest, CaptureScopedRefPtrAsScopedRefPtr) {
179   LifeTimeCheck object;
180   EXPECT_EQ(object.ref_count_, 0);
181   scoped_refptr<LifeTimeCheck> scoped_object(&object);
182   EXPECT_EQ(object.ref_count_, 1);
183   {
184     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);
188   }
189   EXPECT_EQ(object.ref_count_, 0);
190 }
191 
192 // Test Bind where method object is captured as scoped_refptr<> and the functor
193 // dies while there are references left.
TEST(BindTest,FunctorReleasesObjectOnDestruction)194 TEST(BindTest, FunctorReleasesObjectOnDestruction) {
195   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.
TEST(BindTest,ScopedRefPointerArgument)206 TEST(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 
222 namespace {
223 
Ref(const int & a)224 const int* Ref(const int& a) { return &a; }
225 
226 }  // anonymous namespace
227 
228 // Test Bind with non-scoped_refptr<> reference argument, which should be
229 // modified to a non-reference capture.
TEST(BindTest,RefArgument)230 TEST(BindTest, RefArgument) {
231   const int x = 42;
232   EXPECT_EQ(&x, Ref(x));
233   // Bind() should make a copy of |x|, i.e. the pointers should be different.
234   auto functor = Bind(&Ref, x);
235   EXPECT_NE(&x, functor());
236 }
237 
238 }  // namespace rtc
239