OLD | NEW |
| (Empty) |
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/run_loop.h" | |
12 #include "base/single_thread_task_runner.h" | |
13 #include "base/threading/thread.h" | |
14 #include "testing/gmock/include/gmock/gmock.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 | |
17 namespace syncer { | |
18 | |
19 using ::testing::_; | |
20 using ::testing::SaveArg; | |
21 using ::testing::StrictMock; | |
22 | |
23 class Base { | |
24 public: | |
25 Base() : weak_ptr_factory_(this) {} | |
26 | |
27 WeakHandle<Base> AsWeakHandle() { | |
28 return MakeWeakHandle(weak_ptr_factory_.GetWeakPtr()); | |
29 } | |
30 | |
31 void Kill() { | |
32 weak_ptr_factory_.InvalidateWeakPtrs(); | |
33 } | |
34 | |
35 MOCK_METHOD0(Test, void()); | |
36 MOCK_METHOD1(Test1, void(const int&)); | |
37 MOCK_METHOD2(Test2, void(const int&, Base*)); | |
38 MOCK_METHOD3(Test3, void(const int&, Base*, float)); | |
39 MOCK_METHOD4(Test4, void(const int&, Base*, float, const char*)); | |
40 | |
41 MOCK_METHOD1(TestWithSelf, void(const WeakHandle<Base>&)); | |
42 | |
43 private: | |
44 base::WeakPtrFactory<Base> weak_ptr_factory_; | |
45 }; | |
46 | |
47 class Derived : public Base, public base::SupportsWeakPtr<Derived> {}; | |
48 | |
49 class WeakHandleTest : public ::testing::Test { | |
50 protected: | |
51 void TearDown() override { | |
52 // Process any last-minute posted tasks. | |
53 PumpLoop(); | |
54 } | |
55 | |
56 void PumpLoop() { | |
57 base::RunLoop().RunUntilIdle(); | |
58 } | |
59 | |
60 static void CallTestFromOtherThread(tracked_objects::Location from_here, | |
61 const WeakHandle<Base>& h) { | |
62 base::Thread t("Test thread"); | |
63 ASSERT_TRUE(t.Start()); | |
64 t.task_runner()->PostTask( | |
65 from_here, base::Bind(&WeakHandleTest::CallTest, from_here, h)); | |
66 } | |
67 | |
68 private: | |
69 static void CallTest(tracked_objects::Location from_here, | |
70 const WeakHandle<Base>& h) { | |
71 h.Call(from_here, &Base::Test); | |
72 } | |
73 | |
74 base::MessageLoop message_loop_; | |
75 }; | |
76 | |
77 TEST_F(WeakHandleTest, Uninitialized) { | |
78 // Default. | |
79 WeakHandle<int> h; | |
80 EXPECT_FALSE(h.IsInitialized()); | |
81 // Copy. | |
82 { | |
83 WeakHandle<int> h2(h); | |
84 EXPECT_FALSE(h2.IsInitialized()); | |
85 } | |
86 // Assign. | |
87 { | |
88 WeakHandle<int> h2; | |
89 h2 = h; | |
90 EXPECT_FALSE(h.IsInitialized()); | |
91 } | |
92 } | |
93 | |
94 TEST_F(WeakHandleTest, InitializedAfterDestroy) { | |
95 WeakHandle<Base> h; | |
96 { | |
97 StrictMock<Base> b; | |
98 h = b.AsWeakHandle(); | |
99 } | |
100 EXPECT_TRUE(h.IsInitialized()); | |
101 EXPECT_FALSE(h.Get()); | |
102 } | |
103 | |
104 TEST_F(WeakHandleTest, InitializedAfterInvalidate) { | |
105 StrictMock<Base> b; | |
106 WeakHandle<Base> h = b.AsWeakHandle(); | |
107 b.Kill(); | |
108 EXPECT_TRUE(h.IsInitialized()); | |
109 EXPECT_FALSE(h.Get()); | |
110 } | |
111 | |
112 TEST_F(WeakHandleTest, Call) { | |
113 StrictMock<Base> b; | |
114 const char test_str[] = "test"; | |
115 EXPECT_CALL(b, Test()); | |
116 EXPECT_CALL(b, Test1(5)); | |
117 EXPECT_CALL(b, Test2(5, &b)); | |
118 EXPECT_CALL(b, Test3(5, &b, 5)); | |
119 EXPECT_CALL(b, Test4(5, &b, 5, test_str)); | |
120 | |
121 WeakHandle<Base> h = b.AsWeakHandle(); | |
122 EXPECT_TRUE(h.IsInitialized()); | |
123 | |
124 // Should run. | |
125 h.Call(FROM_HERE, &Base::Test); | |
126 h.Call(FROM_HERE, &Base::Test1, 5); | |
127 h.Call(FROM_HERE, &Base::Test2, 5, &b); | |
128 h.Call(FROM_HERE, &Base::Test3, 5, &b, 5); | |
129 h.Call(FROM_HERE, &Base::Test4, 5, &b, 5, test_str); | |
130 PumpLoop(); | |
131 } | |
132 | |
133 TEST_F(WeakHandleTest, CallAfterDestroy) { | |
134 { | |
135 StrictMock<Base> b; | |
136 EXPECT_CALL(b, Test()).Times(0); | |
137 | |
138 WeakHandle<Base> h = b.AsWeakHandle(); | |
139 EXPECT_TRUE(h.IsInitialized()); | |
140 | |
141 // Should not run. | |
142 h.Call(FROM_HERE, &Base::Test); | |
143 } | |
144 PumpLoop(); | |
145 } | |
146 | |
147 TEST_F(WeakHandleTest, CallAfterInvalidate) { | |
148 StrictMock<Base> b; | |
149 EXPECT_CALL(b, Test()).Times(0); | |
150 | |
151 WeakHandle<Base> h = b.AsWeakHandle(); | |
152 EXPECT_TRUE(h.IsInitialized()); | |
153 | |
154 // Should not run. | |
155 h.Call(FROM_HERE, &Base::Test); | |
156 | |
157 b.Kill(); | |
158 PumpLoop(); | |
159 } | |
160 | |
161 TEST_F(WeakHandleTest, CallThreaded) { | |
162 StrictMock<Base> b; | |
163 EXPECT_CALL(b, Test()); | |
164 | |
165 WeakHandle<Base> h = b.AsWeakHandle(); | |
166 // Should run. | |
167 CallTestFromOtherThread(FROM_HERE, h); | |
168 PumpLoop(); | |
169 } | |
170 | |
171 TEST_F(WeakHandleTest, CallAfterDestroyThreaded) { | |
172 WeakHandle<Base> h; | |
173 { | |
174 StrictMock<Base> b; | |
175 EXPECT_CALL(b, Test()).Times(0); | |
176 h = b.AsWeakHandle(); | |
177 } | |
178 | |
179 // Should not run. | |
180 CallTestFromOtherThread(FROM_HERE, h); | |
181 PumpLoop(); | |
182 } | |
183 | |
184 TEST_F(WeakHandleTest, CallAfterInvalidateThreaded) { | |
185 StrictMock<Base> b; | |
186 EXPECT_CALL(b, Test()).Times(0); | |
187 | |
188 WeakHandle<Base> h = b.AsWeakHandle(); | |
189 b.Kill(); | |
190 // Should not run. | |
191 CallTestFromOtherThread(FROM_HERE, h); | |
192 PumpLoop(); | |
193 } | |
194 | |
195 TEST_F(WeakHandleTest, DeleteOnOtherThread) { | |
196 StrictMock<Base> b; | |
197 EXPECT_CALL(b, Test()).Times(0); | |
198 | |
199 WeakHandle<Base>* h = new WeakHandle<Base>(b.AsWeakHandle()); | |
200 | |
201 { | |
202 base::Thread t("Test thread"); | |
203 ASSERT_TRUE(t.Start()); | |
204 t.task_runner()->DeleteSoon(FROM_HERE, h); | |
205 } | |
206 | |
207 PumpLoop(); | |
208 } | |
209 | |
210 void CallTestWithSelf(const WeakHandle<Base>& b1) { | |
211 StrictMock<Base> b2; | |
212 b1.Call(FROM_HERE, &Base::TestWithSelf, b2.AsWeakHandle()); | |
213 } | |
214 | |
215 TEST_F(WeakHandleTest, WithDestroyedThread) { | |
216 StrictMock<Base> b1; | |
217 WeakHandle<Base> b2; | |
218 EXPECT_CALL(b1, TestWithSelf(_)).WillOnce(SaveArg<0>(&b2)); | |
219 | |
220 { | |
221 base::Thread t("Test thread"); | |
222 ASSERT_TRUE(t.Start()); | |
223 t.task_runner()->PostTask(FROM_HERE, | |
224 base::Bind(&CallTestWithSelf, 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 | |
OLD | NEW |