Chromium Code Reviews| Index: webrtc/base/bind_unittest.cc |
| diff --git a/webrtc/base/bind_unittest.cc b/webrtc/base/bind_unittest.cc |
| index 7a621dce2cb37c8e4301dc47bb3501da0b26976d..d38729d9df20b64eb06484d94ffbece584321ec0 100644 |
| --- a/webrtc/base/bind_unittest.cc |
| +++ b/webrtc/base/bind_unittest.cc |
| @@ -17,6 +17,8 @@ namespace rtc { |
| namespace { |
| +struct LifeTimeCheck; |
| + |
| struct MethodBindTester { |
| void NullaryVoid() { ++call_count; } |
| int NullaryInt() { ++call_count; return 1; } |
| @@ -25,6 +27,10 @@ struct MethodBindTester { |
| template <class T> T Identity(T value) { ++call_count; return value; } |
| int UnaryByRef(int& value) const { ++call_count; return ++value; } // NOLINT |
| int Multiply(int a, int b) const { ++call_count; return a * b; } |
| + void RefArgument(const scoped_refptr<LifeTimeCheck>& object) { |
| + EXPECT_TRUE(object.get() != nullptr); |
| + } |
| + |
| mutable int call_count; |
| }; |
| @@ -42,19 +48,12 @@ struct F { |
| 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; } |
| +struct LifeTimeCheck { |
| + LifeTimeCheck() : ref_count_(0) {} |
| + void AddRef() { ++ref_count_; } |
| + void Release() { --ref_count_; } |
| void NullaryVoid() {} |
| - |
| - private: |
| - bool* const has_died_; |
| - bool is_ok_to_die_; |
| + int ref_count_; |
| }; |
| int Return42() { return 42; } |
| @@ -65,6 +64,27 @@ int Multiply(int a, int b) { return a * b; } |
| // Try to catch any problem with scoped_refptr type deduction in rtc::Bind at |
| // compile time. |
| +static_assert(is_same<detail::RemoveScopedPtrRef< |
|
tommi
2015/08/24 15:43:31
these are nice
|
| + const scoped_refptr<RefCountInterface>&>::type, |
| + scoped_refptr<RefCountInterface>>::value, |
| + "const scoped_refptr& should be captured by value"); |
| + |
| +static_assert(is_same<detail::RemoveScopedPtrRef<const scoped_refptr<F>&>::type, |
| + scoped_refptr<F>>::value, |
| + "const scoped_refptr& should be captured by value"); |
| + |
| +static_assert( |
| + is_same<detail::RemoveScopedPtrRef<const int&>::type, const int&>::value, |
| + "const int& should be captured as const int&"); |
| + |
| +static_assert( |
| + is_same<detail::RemoveScopedPtrRef<const F&>::type, const F&>::value, |
| + "const F& should be captured as const F&"); |
| + |
| +static_assert( |
| + is_same<detail::RemoveScopedPtrRef<F&>::type, F&>::value, |
| + "F& should be captured as F&"); |
| + |
| #define EXPECT_IS_CAPTURED_AS_PTR(T) \ |
| static_assert(is_same<detail::PointerType<T>::type, T*>::value, \ |
| "PointerType") |
| @@ -124,46 +144,78 @@ TEST(BindTest, BindToFunction) { |
| // 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); |
| + LifeTimeCheck object; |
| + EXPECT_EQ(object.ref_count_, 0); |
| + scoped_refptr<LifeTimeCheck> scoped_object(&object); |
| + EXPECT_EQ(object.ref_count_, 1); |
| { |
| - auto functor = Bind(&LifeTimeCheck::PrepareToDie, object.get()); |
| - object = nullptr; |
| - EXPECT_FALSE(object_has_died); |
| - // Run prepare to die via functor. |
| - functor(); |
| + auto functor = Bind(&LifeTimeCheck::NullaryVoid, &object); |
| + EXPECT_EQ(object.ref_count_, 2); |
| + scoped_object = nullptr; |
| + EXPECT_EQ(object.ref_count_, 1); |
| } |
| - EXPECT_TRUE(object_has_died); |
| + EXPECT_EQ(object.ref_count_, 0); |
| } |
| // 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); |
| + LifeTimeCheck object; |
| + EXPECT_EQ(object.ref_count_, 0); |
| + scoped_refptr<LifeTimeCheck> scoped_object(&object); |
| + EXPECT_EQ(object.ref_count_, 1); |
| { |
| - auto functor = Bind(&LifeTimeCheck::PrepareToDie, object); |
| - object = nullptr; |
| - EXPECT_FALSE(object_has_died); |
| - // Run prepare to die via functor. |
| - functor(); |
| + auto functor = Bind(&LifeTimeCheck::NullaryVoid, scoped_object); |
| + EXPECT_EQ(object.ref_count_, 2); |
| + scoped_object = nullptr; |
| + EXPECT_EQ(object.ref_count_, 1); |
| } |
| - EXPECT_TRUE(object_has_died); |
| + EXPECT_EQ(object.ref_count_, 0); |
| } |
| // 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); |
| + LifeTimeCheck object; |
| + EXPECT_EQ(object.ref_count_, 0); |
| + scoped_refptr<LifeTimeCheck> scoped_object(&object); |
| + EXPECT_EQ(object.ref_count_, 1); |
| + Bind(&LifeTimeCheck::NullaryVoid, &object)(); |
| + EXPECT_EQ(object.ref_count_, 1); |
| + scoped_object = nullptr; |
| + EXPECT_EQ(object.ref_count_, 0); |
| +} |
| + |
| +// Test Bind with scoped_refptr<> argument. |
| +TEST(BindTest, ScopedRefPointerArgument) { |
| + LifeTimeCheck object; |
| + EXPECT_EQ(object.ref_count_, 0); |
| + scoped_refptr<LifeTimeCheck> scoped_object(&object); |
| + EXPECT_EQ(object.ref_count_, 1); |
| + { |
| + MethodBindTester bind_tester; |
| + auto functor = |
| + Bind(&MethodBindTester::RefArgument, &bind_tester, scoped_object); |
| + EXPECT_EQ(object.ref_count_, 2); |
| + } |
| + EXPECT_EQ(object.ref_count_, 1); |
| + scoped_object = nullptr; |
| + EXPECT_EQ(object.ref_count_, 0); |
| +} |
| + |
| +namespace { |
| + |
| +const int* Ref(const int& a) { return &a; } |
| + |
| +} // anonymous namespace |
| + |
| +// Test Bind with non-scoped_refptr<> reference argument. |
| +TEST(BindTest, RefArgument) { |
| + const int x = 42; |
| + EXPECT_TRUE(Ref(x) == &x); |
| + // Bind() should not make a copy of |x|, i.e. the pointers should be the same. |
| + auto functor = Bind(&Ref, x); |
| + EXPECT_TRUE(functor() == &x); |
| } |
| } // namespace rtc |