Home | History | Annotate | Download | only in util
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "sync/internal_api/public/util/weak_handle.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/compiler_specific.h"
      9 #include "base/location.h"
     10 #include "base/memory/weak_ptr.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/threading/thread.h"
     13 #include "testing/gmock/include/gmock/gmock.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 
     16 namespace syncer {
     17 
     18 using ::testing::_;
     19 using ::testing::SaveArg;
     20 using ::testing::StrictMock;
     21 
     22 class Base {
     23  public:
     24   Base() : weak_ptr_factory_(this) {}
     25 
     26   WeakHandle<Base> AsWeakHandle() {
     27     return MakeWeakHandle(weak_ptr_factory_.GetWeakPtr());
     28   }
     29 
     30   void Kill() {
     31     weak_ptr_factory_.InvalidateWeakPtrs();
     32   }
     33 
     34   MOCK_METHOD0(Test, void());
     35   MOCK_METHOD1(Test1, void(const int&));
     36   MOCK_METHOD2(Test2, void(const int&, Base*));
     37   MOCK_METHOD3(Test3, void(const int&, Base*, float));
     38   MOCK_METHOD4(Test4, void(const int&, Base*, float, const char*));
     39 
     40   MOCK_METHOD1(TestWithSelf, void(const WeakHandle<Base>&));
     41 
     42  private:
     43   base::WeakPtrFactory<Base> weak_ptr_factory_;
     44 };
     45 
     46 class Derived : public Base, public base::SupportsWeakPtr<Derived> {};
     47 
     48 class WeakHandleTest : public ::testing::Test {
     49  protected:
     50   virtual void TearDown() {
     51     // Process any last-minute posted tasks.
     52     PumpLoop();
     53   }
     54 
     55   void PumpLoop() {
     56     message_loop_.RunUntilIdle();
     57   }
     58 
     59   static void CallTestFromOtherThread(tracked_objects::Location from_here,
     60                                       const WeakHandle<Base>& h) {
     61     base::Thread t("Test thread");
     62     ASSERT_TRUE(t.Start());
     63     t.message_loop()->PostTask(
     64         from_here, base::Bind(&WeakHandleTest::CallTest, from_here, h));
     65   }
     66 
     67  private:
     68   static void CallTest(tracked_objects::Location from_here,
     69                        const WeakHandle<Base>& h) {
     70     h.Call(from_here, &Base::Test);
     71   }
     72 
     73   base::MessageLoop message_loop_;
     74 };
     75 
     76 TEST_F(WeakHandleTest, Uninitialized) {
     77   // Default.
     78   WeakHandle<int> h;
     79   EXPECT_FALSE(h.IsInitialized());
     80   // Copy.
     81   {
     82     WeakHandle<int> h2(h);
     83     EXPECT_FALSE(h2.IsInitialized());
     84   }
     85   // Assign.
     86   {
     87     WeakHandle<int> h2;
     88     h2 = h;
     89     EXPECT_FALSE(h.IsInitialized());
     90   }
     91 }
     92 
     93 TEST_F(WeakHandleTest, InitializedAfterDestroy) {
     94   WeakHandle<Base> h;
     95   {
     96     StrictMock<Base> b;
     97     h = b.AsWeakHandle();
     98   }
     99   EXPECT_TRUE(h.IsInitialized());
    100   EXPECT_FALSE(h.Get());
    101 }
    102 
    103 TEST_F(WeakHandleTest, InitializedAfterInvalidate) {
    104   StrictMock<Base> b;
    105   WeakHandle<Base> h = b.AsWeakHandle();
    106   b.Kill();
    107   EXPECT_TRUE(h.IsInitialized());
    108   EXPECT_FALSE(h.Get());
    109 }
    110 
    111 TEST_F(WeakHandleTest, Call) {
    112   StrictMock<Base> b;
    113   const char test_str[] = "test";
    114   EXPECT_CALL(b, Test());
    115   EXPECT_CALL(b, Test1(5));
    116   EXPECT_CALL(b, Test2(5, &b));
    117   EXPECT_CALL(b, Test3(5, &b, 5));
    118   EXPECT_CALL(b, Test4(5, &b, 5, test_str));
    119 
    120   WeakHandle<Base> h = b.AsWeakHandle();
    121   EXPECT_TRUE(h.IsInitialized());
    122 
    123   // Should run.
    124   h.Call(FROM_HERE, &Base::Test);
    125   h.Call(FROM_HERE, &Base::Test1, 5);
    126   h.Call(FROM_HERE, &Base::Test2, 5, &b);
    127   h.Call(FROM_HERE, &Base::Test3, 5, &b, 5);
    128   h.Call(FROM_HERE, &Base::Test4, 5, &b, 5, test_str);
    129   PumpLoop();
    130 }
    131 
    132 TEST_F(WeakHandleTest, CallAfterDestroy) {
    133   {
    134     StrictMock<Base> b;
    135     EXPECT_CALL(b, Test()).Times(0);
    136 
    137     WeakHandle<Base> h = b.AsWeakHandle();
    138     EXPECT_TRUE(h.IsInitialized());
    139 
    140     // Should not run.
    141     h.Call(FROM_HERE, &Base::Test);
    142   }
    143   PumpLoop();
    144 }
    145 
    146 TEST_F(WeakHandleTest, CallAfterInvalidate) {
    147   StrictMock<Base> b;
    148   EXPECT_CALL(b, Test()).Times(0);
    149 
    150   WeakHandle<Base> h = b.AsWeakHandle();
    151   EXPECT_TRUE(h.IsInitialized());
    152 
    153   // Should not run.
    154   h.Call(FROM_HERE, &Base::Test);
    155 
    156   b.Kill();
    157   PumpLoop();
    158 }
    159 
    160 TEST_F(WeakHandleTest, CallThreaded) {
    161   StrictMock<Base> b;
    162   EXPECT_CALL(b, Test());
    163 
    164   WeakHandle<Base> h = b.AsWeakHandle();
    165   // Should run.
    166   CallTestFromOtherThread(FROM_HERE, h);
    167   PumpLoop();
    168 }
    169 
    170 TEST_F(WeakHandleTest, CallAfterDestroyThreaded) {
    171   WeakHandle<Base> h;
    172   {
    173     StrictMock<Base> b;
    174     EXPECT_CALL(b, Test()).Times(0);
    175     h = b.AsWeakHandle();
    176   }
    177 
    178   // Should not run.
    179   CallTestFromOtherThread(FROM_HERE, h);
    180   PumpLoop();
    181 }
    182 
    183 TEST_F(WeakHandleTest, CallAfterInvalidateThreaded) {
    184   StrictMock<Base> b;
    185   EXPECT_CALL(b, Test()).Times(0);
    186 
    187   WeakHandle<Base> h = b.AsWeakHandle();
    188   b.Kill();
    189   // Should not run.
    190   CallTestFromOtherThread(FROM_HERE, h);
    191   PumpLoop();
    192 }
    193 
    194 TEST_F(WeakHandleTest, DeleteOnOtherThread) {
    195   StrictMock<Base> b;
    196   EXPECT_CALL(b, Test()).Times(0);
    197 
    198   WeakHandle<Base>* h = new WeakHandle<Base>(b.AsWeakHandle());
    199 
    200   {
    201     base::Thread t("Test thread");
    202     ASSERT_TRUE(t.Start());
    203     t.message_loop()->DeleteSoon(FROM_HERE, h);
    204   }
    205 
    206   PumpLoop();
    207 }
    208 
    209 void CallTestWithSelf(const WeakHandle<Base>& b1) {
    210   StrictMock<Base> b2;
    211   b1.Call(FROM_HERE, &Base::TestWithSelf, b2.AsWeakHandle());
    212 }
    213 
    214 TEST_F(WeakHandleTest, WithDestroyedThread) {
    215   StrictMock<Base> b1;
    216   WeakHandle<Base> b2;
    217   EXPECT_CALL(b1, TestWithSelf(_)).WillOnce(SaveArg<0>(&b2));
    218 
    219   {
    220     base::Thread t("Test thread");
    221     ASSERT_TRUE(t.Start());
    222     t.message_loop()->PostTask(FROM_HERE,
    223                                base::Bind(&CallTestWithSelf,
    224                                           b1.AsWeakHandle()));
    225   }
    226 
    227   // Calls b1.TestWithSelf().
    228   PumpLoop();
    229 
    230   // Shouldn't do anything, since the thread is gone.
    231   b2.Call(FROM_HERE, &Base::Test);
    232 
    233   // |b2| shouldn't leak when it's destroyed, even if the original
    234   // thread is gone.
    235 }
    236 
    237 TEST_F(WeakHandleTest, InitializedAcrossCopyAssign) {
    238   StrictMock<Base> b;
    239   EXPECT_CALL(b, Test()).Times(3);
    240 
    241   EXPECT_TRUE(b.AsWeakHandle().IsInitialized());
    242   b.AsWeakHandle().Call(FROM_HERE, &Base::Test);
    243 
    244   {
    245     WeakHandle<Base> h(b.AsWeakHandle());
    246     EXPECT_TRUE(h.IsInitialized());
    247     h.Call(FROM_HERE, &Base::Test);
    248     h.Reset();
    249     EXPECT_FALSE(h.IsInitialized());
    250   }
    251 
    252   {
    253     WeakHandle<Base> h;
    254     h = b.AsWeakHandle();
    255     EXPECT_TRUE(h.IsInitialized());
    256     h.Call(FROM_HERE, &Base::Test);
    257     h.Reset();
    258     EXPECT_FALSE(h.IsInitialized());
    259   }
    260 
    261   PumpLoop();
    262 }
    263 
    264 TEST_F(WeakHandleTest, TypeConversionConstructor) {
    265   StrictMock<Derived> d;
    266   EXPECT_CALL(d, Test()).Times(2);
    267 
    268   const WeakHandle<Derived> weak_handle = MakeWeakHandle(d.AsWeakPtr());
    269 
    270   // Should trigger type conversion constructor.
    271   const WeakHandle<Base> base_weak_handle(weak_handle);
    272   // Should trigger regular copy constructor.
    273   const WeakHandle<Derived> derived_weak_handle(weak_handle);
    274 
    275   EXPECT_TRUE(base_weak_handle.IsInitialized());
    276   base_weak_handle.Call(FROM_HERE, &Base::Test);
    277 
    278   EXPECT_TRUE(derived_weak_handle.IsInitialized());
    279   // Copy constructor shouldn't construct a new |core_|.
    280   EXPECT_EQ(weak_handle.core_.get(), derived_weak_handle.core_.get());
    281   derived_weak_handle.Call(FROM_HERE, &Base::Test);
    282 
    283   PumpLoop();
    284 }
    285 
    286 TEST_F(WeakHandleTest, TypeConversionConstructorMakeWeakHandle) {
    287   const base::WeakPtr<Derived> weak_ptr;
    288 
    289   // Should trigger type conversion constructor after MakeWeakHandle.
    290   WeakHandle<Base> base_weak_handle(MakeWeakHandle(weak_ptr));
    291   // Should trigger regular copy constructor after MakeWeakHandle.
    292   const WeakHandle<Derived> derived_weak_handle(MakeWeakHandle(weak_ptr));
    293 
    294   EXPECT_TRUE(base_weak_handle.IsInitialized());
    295   EXPECT_TRUE(derived_weak_handle.IsInitialized());
    296 }
    297 
    298 TEST_F(WeakHandleTest, TypeConversionConstructorAssignment) {
    299   const WeakHandle<Derived> weak_handle =
    300       MakeWeakHandle(Derived().AsWeakPtr());
    301 
    302   // Should trigger type conversion constructor before the assignment.
    303   WeakHandle<Base> base_weak_handle;
    304   base_weak_handle = weak_handle;
    305   // Should trigger regular copy constructor before the assignment.
    306   WeakHandle<Derived> derived_weak_handle;
    307   derived_weak_handle = weak_handle;
    308 
    309   EXPECT_TRUE(base_weak_handle.IsInitialized());
    310   EXPECT_TRUE(derived_weak_handle.IsInitialized());
    311   // Copy constructor shouldn't construct a new |core_|.
    312   EXPECT_EQ(weak_handle.core_.get(), derived_weak_handle.core_.get());
    313 }
    314 
    315 TEST_F(WeakHandleTest, TypeConversionConstructorUninitialized) {
    316   const WeakHandle<Base> base_weak_handle = WeakHandle<Derived>();
    317   EXPECT_FALSE(base_weak_handle.IsInitialized());
    318 }
    319 
    320 TEST_F(WeakHandleTest, TypeConversionConstructorUninitializedAssignment) {
    321   WeakHandle<Base> base_weak_handle;
    322   base_weak_handle = WeakHandle<Derived>();
    323   EXPECT_FALSE(base_weak_handle.IsInitialized());
    324 }
    325 
    326 }  // namespace syncer
    327