• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
Base()24   Base() : weak_ptr_factory_(this) {}
25 
AsWeakHandle()26   WeakHandle<Base> AsWeakHandle() {
27     return MakeWeakHandle(weak_ptr_factory_.GetWeakPtr());
28   }
29 
Kill()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:
TearDown()50   virtual void TearDown() {
51     // Process any last-minute posted tasks.
52     PumpLoop();
53   }
54 
PumpLoop()55   void PumpLoop() {
56     message_loop_.RunUntilIdle();
57   }
58 
CallTestFromOtherThread(tracked_objects::Location from_here,const WeakHandle<Base> & h)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:
CallTest(tracked_objects::Location from_here,const WeakHandle<Base> & h)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 
TEST_F(WeakHandleTest,Uninitialized)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 
TEST_F(WeakHandleTest,InitializedAfterDestroy)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 
TEST_F(WeakHandleTest,InitializedAfterInvalidate)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 
TEST_F(WeakHandleTest,Call)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 
TEST_F(WeakHandleTest,CallAfterDestroy)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 
TEST_F(WeakHandleTest,CallAfterInvalidate)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 
TEST_F(WeakHandleTest,CallThreaded)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 
TEST_F(WeakHandleTest,CallAfterDestroyThreaded)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 
TEST_F(WeakHandleTest,CallAfterInvalidateThreaded)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 
TEST_F(WeakHandleTest,DeleteOnOtherThread)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 
CallTestWithSelf(const WeakHandle<Base> & b1)209 void CallTestWithSelf(const WeakHandle<Base>& b1) {
210   StrictMock<Base> b2;
211   b1.Call(FROM_HERE, &Base::TestWithSelf, b2.AsWeakHandle());
212 }
213 
TEST_F(WeakHandleTest,WithDestroyedThread)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 
TEST_F(WeakHandleTest,InitializedAcrossCopyAssign)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 
TEST_F(WeakHandleTest,TypeConversionConstructor)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 
TEST_F(WeakHandleTest,TypeConversionConstructorMakeWeakHandle)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 
TEST_F(WeakHandleTest,TypeConversionConstructorAssignment)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 
TEST_F(WeakHandleTest,TypeConversionConstructorUninitialized)315 TEST_F(WeakHandleTest, TypeConversionConstructorUninitialized) {
316   const WeakHandle<Base> base_weak_handle = WeakHandle<Derived>();
317   EXPECT_FALSE(base_weak_handle.IsInitialized());
318 }
319 
TEST_F(WeakHandleTest,TypeConversionConstructorUninitializedAssignment)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