Index: webrtc/base/bind_unittest.cc |
diff --git a/webrtc/base/bind_unittest.cc b/webrtc/base/bind_unittest.cc |
index ed8dd5cf2d226a93b24512069bc9324aa9c91619..7a621dce2cb37c8e4301dc47bb3501da0b26976d 100644 |
--- a/webrtc/base/bind_unittest.cc |
+++ b/webrtc/base/bind_unittest.cc |
@@ -11,6 +11,8 @@ |
#include "webrtc/base/bind.h" |
#include "webrtc/base/gunit.h" |
+#include "webrtc/base/refcount.h" |
+ |
namespace rtc { |
namespace { |
@@ -26,12 +28,67 @@ struct MethodBindTester { |
mutable int call_count; |
}; |
+struct A { int dummy; }; |
+struct B: public RefCountInterface { int dummy; }; |
+struct C: public A, B {}; |
+struct D { |
+ int AddRef(); |
+}; |
+struct E: public D { |
+ int Release(); |
+}; |
+struct F { |
+ void AddRef(); |
+ void Release(); |
+}; |
+ |
+class LifeTimeCheck : public RefCountInterface { |
+ public: |
+ LifeTimeCheck(bool* has_died) : has_died_(has_died), is_ok_to_die_(false) {} |
+ ~LifeTimeCheck() { |
+ EXPECT_TRUE(is_ok_to_die_); |
+ *has_died_ = true; |
+ } |
+ void PrepareToDie() { is_ok_to_die_ = true; } |
+ void NullaryVoid() {} |
+ |
+ private: |
+ bool* const has_died_; |
+ bool is_ok_to_die_; |
+}; |
+ |
int Return42() { return 42; } |
int Negate(int a) { return -a; } |
int Multiply(int a, int b) { return a * b; } |
} // namespace |
+// Try to catch any problem with scoped_refptr type deduction in rtc::Bind at |
+// compile time. |
+#define EXPECT_IS_CAPTURED_AS_PTR(T) \ |
+ static_assert(is_same<detail::PointerType<T>::type, T*>::value, \ |
+ "PointerType") |
+#define EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(T) \ |
+ static_assert( \ |
+ is_same<detail::PointerType<T>::type, scoped_refptr<T>>::value, \ |
+ "PointerType") |
+ |
+EXPECT_IS_CAPTURED_AS_PTR(void); |
+EXPECT_IS_CAPTURED_AS_PTR(int); |
+EXPECT_IS_CAPTURED_AS_PTR(double); |
+EXPECT_IS_CAPTURED_AS_PTR(A); |
+EXPECT_IS_CAPTURED_AS_PTR(D); |
+EXPECT_IS_CAPTURED_AS_PTR(RefCountInterface*); |
+ |
+EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountInterface); |
+EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(B); |
+EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(C); |
+EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(E); |
+EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(F); |
+EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<RefCountInterface>); |
+EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<B>); |
+EXPECT_IS_CAPTURED_AS_SCOPED_REFPTR(RefCountedObject<C>); |
+ |
TEST(BindTest, BindToMethod) { |
MethodBindTester object = {0}; |
EXPECT_EQ(0, object.call_count); |
@@ -64,4 +121,49 @@ TEST(BindTest, BindToFunction) { |
EXPECT_EQ(56, Bind(&Multiply, 8, 7)()); |
} |
+// Test Bind where method object implements RefCountInterface and is passed as a |
+// pointer. |
+TEST(BindTest, CapturePointerAsScopedRefPtr) { |
+ bool object_has_died = false; |
+ scoped_refptr<LifeTimeCheck> object = |
+ new RefCountedObject<LifeTimeCheck>(&object_has_died); |
+ { |
+ auto functor = Bind(&LifeTimeCheck::PrepareToDie, object.get()); |
+ object = nullptr; |
+ EXPECT_FALSE(object_has_died); |
+ // Run prepare to die via functor. |
+ functor(); |
+ } |
+ EXPECT_TRUE(object_has_died); |
+} |
+ |
+// Test Bind where method object implements RefCountInterface and is passed as a |
+// scoped_refptr<>. |
+TEST(BindTest, CaptureScopedRefPtrAsScopedRefPtr) { |
+ bool object_has_died = false; |
+ scoped_refptr<LifeTimeCheck> object = |
+ new RefCountedObject<LifeTimeCheck>(&object_has_died); |
+ { |
+ auto functor = Bind(&LifeTimeCheck::PrepareToDie, object); |
+ object = nullptr; |
+ EXPECT_FALSE(object_has_died); |
+ // Run prepare to die via functor. |
+ functor(); |
+ } |
+ EXPECT_TRUE(object_has_died); |
+} |
+ |
+// Test Bind where method object is captured as scoped_refptr<> and the functor |
+// dies while there are references left. |
+TEST(BindTest, FunctorReleasesObjectOnDestruction) { |
+ bool object_has_died = false; |
+ scoped_refptr<LifeTimeCheck> object = |
+ new RefCountedObject<LifeTimeCheck>(&object_has_died); |
+ Bind(&LifeTimeCheck::NullaryVoid, object.get())(); |
+ EXPECT_FALSE(object_has_died); |
+ object->PrepareToDie(); |
+ object = nullptr; |
+ EXPECT_TRUE(object_has_died); |
+} |
+ |
} // namespace rtc |