OLD | NEW |
| (Empty) |
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 <type_traits> | |
12 | |
13 #include "webrtc/base/bind.h" | |
14 #include "webrtc/base/gunit.h" | |
15 | |
16 #include "webrtc/base/refcount.h" | |
17 | |
18 namespace rtc { | |
19 | |
20 namespace { | |
21 | |
22 struct LifeTimeCheck; | |
23 | |
24 struct MethodBindTester { | |
25 void NullaryVoid() { ++call_count; } | |
26 int NullaryInt() { ++call_count; return 1; } | |
27 int NullaryConst() const { ++call_count; return 2; } | |
28 void UnaryVoid(int dummy) { ++call_count; } | |
29 template <class T> T Identity(T value) { ++call_count; return value; } | |
30 int UnaryByPointer(int* value) const { | |
31 ++call_count; | |
32 return ++(*value); | |
33 } | |
34 int UnaryByRef(const int& value) const { | |
35 ++call_count; | |
36 return ++const_cast<int&>(value); | |
37 } | |
38 int Multiply(int a, int b) const { ++call_count; return a * b; } | |
39 void RefArgument(const scoped_refptr<LifeTimeCheck>& object) { | |
40 EXPECT_TRUE(object.get() != nullptr); | |
41 } | |
42 | |
43 mutable int call_count; | |
44 }; | |
45 | |
46 struct A { int dummy; }; | |
47 struct B: public RefCountInterface { int dummy; }; | |
48 struct C: public A, B {}; | |
49 struct D { | |
50 int AddRef(); | |
51 }; | |
52 struct E: public D { | |
53 int Release(); | |
54 }; | |
55 struct F { | |
56 void AddRef(); | |
57 void Release(); | |
58 }; | |
59 | |
60 struct LifeTimeCheck { | |
61 LifeTimeCheck() : ref_count_(0) {} | |
62 void AddRef() { ++ref_count_; } | |
63 void Release() { --ref_count_; } | |
64 void NullaryVoid() {} | |
65 int ref_count_; | |
66 }; | |
67 | |
68 int Return42() { return 42; } | |
69 int Negate(int a) { return -a; } | |
70 int Multiply(int a, int b) { return a * b; } | |
71 | |
72 } // namespace | |
73 | |
74 // Try to catch any problem with scoped_refptr type deduction in rtc::Bind at | |
75 // compile time. | |
76 #define EXPECT_IS_CAPTURED_AS_PTR(T) \ | |
77 static_assert(is_same<detail::PointerType<T>::type, T*>::value, \ | |
78 "PointerType") | |
79 #define EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(T) \ | |
80 static_assert( \ | |
81 is_same<detail::PointerType<T>::type, scoped_refptr<T>>::value, \ | |
82 "PointerType") | |
83 | |
84 EXPECT_IS_CAPTURED_AS_PTR(void); | |
85 EXPECT_IS_CAPTURED_AS_PTR(int); | |
86 EXPECT_IS_CAPTURED_AS_PTR(double); | |
87 EXPECT_IS_CAPTURED_AS_PTR(A); | |
88 EXPECT_IS_CAPTURED_AS_PTR(D); | |
89 EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*); | |
90 EXPECT_IS_CAPTURED_AS_PTR( | |
91 decltype(Unretained<RefCountedObject<RefCountInterface>>)); | |
92 | |
93 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface); | |
94 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B); | |
95 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(C); | |
96 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(E); | |
97 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(F); | |
98 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<RefCountInterface>); | |
99 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<B>); | |
100 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<C>); | |
101 EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(const RefCountedObject<RefCountInterface>); | |
102 | |
103 TEST(BindTest, BindToMethod) { | |
104 MethodBindTester object = {0}; | |
105 EXPECT_EQ(0, object.call_count); | |
106 Bind(&MethodBindTester::NullaryVoid, &object)(); | |
107 EXPECT_EQ(1, object.call_count); | |
108 EXPECT_EQ(1, Bind(&MethodBindTester::NullaryInt, &object)()); | |
109 EXPECT_EQ(2, object.call_count); | |
110 EXPECT_EQ(2, Bind(&MethodBindTester::NullaryConst, | |
111 static_cast<const MethodBindTester*>(&object))()); | |
112 EXPECT_EQ(3, object.call_count); | |
113 Bind(&MethodBindTester::UnaryVoid, &object, 5)(); | |
114 EXPECT_EQ(4, object.call_count); | |
115 EXPECT_EQ(100, Bind(&MethodBindTester::Identity<int>, &object, 100)()); | |
116 EXPECT_EQ(5, object.call_count); | |
117 const std::string string_value("test string"); | |
118 EXPECT_EQ(string_value, Bind(&MethodBindTester::Identity<std::string>, | |
119 &object, string_value)()); | |
120 EXPECT_EQ(6, object.call_count); | |
121 int value = 11; | |
122 // Bind binds by value, even if the method signature is by reference, so | |
123 // "reference" binds require pointers. | |
124 EXPECT_EQ(12, Bind(&MethodBindTester::UnaryByPointer, &object, &value)()); | |
125 EXPECT_EQ(12, value); | |
126 EXPECT_EQ(7, object.call_count); | |
127 // It's possible to bind to a function that takes a const reference, though | |
128 // the capture will be a copy. See UnaryByRef hackery above where it removes | |
129 // the const to make sure the underlying storage is, in fact, a copy. | |
130 EXPECT_EQ(13, Bind(&MethodBindTester::UnaryByRef, &object, value)()); | |
131 // But the original value is unmodified. | |
132 EXPECT_EQ(12, value); | |
133 EXPECT_EQ(8, object.call_count); | |
134 EXPECT_EQ(56, Bind(&MethodBindTester::Multiply, &object, 7, 8)()); | |
135 EXPECT_EQ(9, object.call_count); | |
136 } | |
137 | |
138 TEST(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 | |
144 // Test Bind where method object implements RefCountInterface and is passed as a | |
145 // pointer. | |
146 TEST(BindTest, CapturePointerAsScopedRefPtr) { | |
147 LifeTimeCheck object; | |
148 EXPECT_EQ(object.ref_count_, 0); | |
149 scoped_refptr<LifeTimeCheck> scoped_object(&object); | |
150 EXPECT_EQ(object.ref_count_, 1); | |
151 { | |
152 auto functor = Bind(&LifeTimeCheck::NullaryVoid, &object); | |
153 EXPECT_EQ(object.ref_count_, 2); | |
154 scoped_object = nullptr; | |
155 EXPECT_EQ(object.ref_count_, 1); | |
156 } | |
157 EXPECT_EQ(object.ref_count_, 0); | |
158 } | |
159 | |
160 // Test Bind where method object implements RefCountInterface and is passed as a | |
161 // scoped_refptr<>. | |
162 TEST(BindTest, CaptureScopedRefPtrAsScopedRefPtr) { | |
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, scoped_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 is captured as scoped_refptr<> and the functor | |
177 // dies while there are references left. | |
178 TEST(BindTest, FunctorReleasesObjectOnDestruction) { | |
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 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. | |
190 TEST(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 | |
206 namespace { | |
207 | |
208 const int* Ref(const int& a) { return &a; } | |
209 | |
210 } // anonymous namespace | |
211 | |
212 // Test Bind with non-scoped_refptr<> reference argument, which should be | |
213 // modified to a non-reference capture. | |
214 TEST(BindTest, RefArgument) { | |
215 const int x = 42; | |
216 EXPECT_EQ(&x, Ref(x)); | |
217 // Bind() should make a copy of |x|, i.e. the pointers should be different. | |
218 auto functor = Bind(&Ref, x); | |
219 EXPECT_NE(&x, functor()); | |
220 } | |
221 | |
222 } // namespace rtc | |
OLD | NEW |