| 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 |