• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "rtc_base/bind.h"
12 
13 #include <string>
14 
15 #include "rtc_base/ref_count.h"
16 #include "rtc_base/ref_counted_object.h"
17 #include "test/gtest.h"
18 
19 namespace rtc {
20 
21 namespace {
22 
23 struct LifeTimeCheck;
24 
25 struct MethodBindTester {
NullaryVoidrtc::__anon926602950111::MethodBindTester26   void NullaryVoid() { ++call_count; }
NullaryIntrtc::__anon926602950111::MethodBindTester27   int NullaryInt() {
28     ++call_count;
29     return 1;
30   }
NullaryConstrtc::__anon926602950111::MethodBindTester31   int NullaryConst() const {
32     ++call_count;
33     return 2;
34   }
UnaryVoidrtc::__anon926602950111::MethodBindTester35   void UnaryVoid(int dummy) { ++call_count; }
36   template <class T>
Identityrtc::__anon926602950111::MethodBindTester37   T Identity(T value) {
38     ++call_count;
39     return value;
40   }
UnaryByPointerrtc::__anon926602950111::MethodBindTester41   int UnaryByPointer(int* value) const {
42     ++call_count;
43     return ++(*value);
44   }
UnaryByRefrtc::__anon926602950111::MethodBindTester45   int UnaryByRef(const int& value) const {
46     ++call_count;
47     return ++const_cast<int&>(value);
48   }
Multiplyrtc::__anon926602950111::MethodBindTester49   int Multiply(int a, int b) const {
50     ++call_count;
51     return a * b;
52   }
RefArgumentrtc::__anon926602950111::MethodBindTester53   void RefArgument(const scoped_refptr<LifeTimeCheck>& object) {
54     EXPECT_TRUE(object.get() != nullptr);
55   }
56 
57   mutable int call_count;
58 };
59 
60 struct A {
61   int dummy;
62 };
63 struct B : public RefCountInterface {
64   int dummy;
65 };
66 struct C : public A, B {};
67 struct D {
68   int AddRef();
69 };
70 struct E : public D {
71   int Release();
72 };
73 struct F {
74   void AddRef();
75   void Release();
76 };
77 
78 struct LifeTimeCheck {
LifeTimeCheckrtc::__anon926602950111::LifeTimeCheck79   LifeTimeCheck() : ref_count_(0) {}
AddRefrtc::__anon926602950111::LifeTimeCheck80   void AddRef() { ++ref_count_; }
Releasertc::__anon926602950111::LifeTimeCheck81   void Release() { --ref_count_; }
NullaryVoidrtc::__anon926602950111::LifeTimeCheck82   void NullaryVoid() {}
83   int ref_count_;
84 };
85 
Return42()86 int Return42() {
87   return 42;
88 }
Negate(int a)89 int Negate(int a) {
90   return -a;
91 }
Multiply(int a,int b)92 int Multiply(int a, int b) {
93   return a * b;
94 }
95 
96 }  // namespace
97 
98 // 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(std::is_same<detail::PointerType<T>::type, T*>::value, \
102                 "PointerType")
103 #define EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(T)                             \
104   static_assert(                                                           \
105       std::is_same<detail::PointerType<T>::type, scoped_refptr<T>>::value, \
106       "PointerType")
107 
108 EXPECT_IS_CAPTURED_AS_PTR(void);
109 EXPECT_IS_CAPTURED_AS_PTR(int);
110 EXPECT_IS_CAPTURED_AS_PTR(double);
111 EXPECT_IS_CAPTURED_AS_PTR(A);
112 EXPECT_IS_CAPTURED_AS_PTR(D);
113 EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*);
114 EXPECT_IS_CAPTURED_AS_PTR(
115     decltype(Unretained<RefCountedObject<RefCountInterface>>));
116 
117 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface);
118 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B);
119 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(C);
120 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(E);
121 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(F);
122 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<RefCountInterface>);
123 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<B>);
124 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<C>);
125 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(const RefCountedObject<RefCountInterface>);
126 
TEST(BindTest,BindToMethod)127 TEST(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;
146   // 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)());
149   EXPECT_EQ(12, value);
150   EXPECT_EQ(7, object.call_count);
151   // 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);
157   EXPECT_EQ(8, object.call_count);
158   EXPECT_EQ(56, Bind(&MethodBindTester::Multiply, &object, 7, 8)());
159   EXPECT_EQ(9, object.call_count);
160 }
161 
TEST(BindTest,BindToFunction)162 TEST(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 
168 // Test Bind where method object implements RefCountInterface and is passed as a
169 // pointer.
TEST(BindTest,CapturePointerAsScopedRefPtr)170 TEST(BindTest, CapturePointerAsScopedRefPtr) {
171   LifeTimeCheck object;
172   EXPECT_EQ(object.ref_count_, 0);
173   scoped_refptr<LifeTimeCheck> scoped_object(&object);
174   EXPECT_EQ(object.ref_count_, 1);
175   {
176     auto functor = Bind(&LifeTimeCheck::NullaryVoid, &object);
177     EXPECT_EQ(object.ref_count_, 2);
178     scoped_object = nullptr;
179     EXPECT_EQ(object.ref_count_, 1);
180   }
181   EXPECT_EQ(object.ref_count_, 0);
182 }
183 
184 // Test Bind where method object implements RefCountInterface and is passed as a
185 // scoped_refptr<>.
TEST(BindTest,CaptureScopedRefPtrAsScopedRefPtr)186 TEST(BindTest, CaptureScopedRefPtrAsScopedRefPtr) {
187   LifeTimeCheck object;
188   EXPECT_EQ(object.ref_count_, 0);
189   scoped_refptr<LifeTimeCheck> scoped_object(&object);
190   EXPECT_EQ(object.ref_count_, 1);
191   {
192     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);
196   }
197   EXPECT_EQ(object.ref_count_, 0);
198 }
199 
200 // Test Bind where method object is captured as scoped_refptr<> and the functor
201 // dies while there are references left.
TEST(BindTest,FunctorReleasesObjectOnDestruction)202 TEST(BindTest, FunctorReleasesObjectOnDestruction) {
203   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.
TEST(BindTest,ScopedRefPointerArgument)214 TEST(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 
230 namespace {
231 
Ref(const int & a)232 const int* Ref(const int& a) {
233   return &a;
234 }
235 
236 }  // anonymous namespace
237 
238 // Test Bind with non-scoped_refptr<> reference argument, which should be
239 // modified to a non-reference capture.
TEST(BindTest,RefArgument)240 TEST(BindTest, RefArgument) {
241   const int x = 42;
242   EXPECT_EQ(&x, Ref(x));
243   // Bind() should make a copy of |x|, i.e. the pointers should be different.
244   auto functor = Bind(&Ref, x);
245   EXPECT_NE(&x, functor());
246 }
247 
248 }  // namespace rtc
249