Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(322)

Side by Side Diff: base/memory/weak_ptr_unittest.cc

Issue 1647803004: Move base to DEPS (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 4 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/memory/weak_ptr.cc ('k') | base/memory/weak_ptr_unittest.nc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 "base/memory/weak_ptr.h"
6
7 #include <string>
8
9 #include "base/bind.h"
10 #include "base/debug/leak_annotations.h"
11 #include "base/location.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/synchronization/waitable_event.h"
15 #include "base/threading/thread.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace base {
19 namespace {
20
21 template <class T>
22 class OffThreadObjectCreator {
23 public:
24 static T* NewObject() {
25 T* result;
26 {
27 Thread creator_thread("creator_thread");
28 creator_thread.Start();
29 creator_thread.task_runner()->PostTask(
30 FROM_HERE, base::Bind(OffThreadObjectCreator::CreateObject, &result));
31 }
32 DCHECK(result); // We synchronized on thread destruction above.
33 return result;
34 }
35 private:
36 static void CreateObject(T** result) {
37 *result = new T;
38 }
39 };
40
41 struct Base {
42 std::string member;
43 };
44 struct Derived : public Base {};
45
46 struct TargetBase {};
47 struct Target : public TargetBase, public SupportsWeakPtr<Target> {
48 virtual ~Target() {}
49 };
50 struct DerivedTarget : public Target {};
51 struct Arrow {
52 WeakPtr<Target> target;
53 };
54 struct TargetWithFactory : public Target {
55 TargetWithFactory() : factory(this) {}
56 WeakPtrFactory<Target> factory;
57 };
58
59 // Helper class to create and destroy weak pointer copies
60 // and delete objects on a background thread.
61 class BackgroundThread : public Thread {
62 public:
63 BackgroundThread() : Thread("owner_thread") {}
64
65 ~BackgroundThread() override { Stop(); }
66
67 void CreateArrowFromTarget(Arrow** arrow, Target* target) {
68 WaitableEvent completion(true, false);
69 task_runner()->PostTask(
70 FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromTarget, arrow,
71 target, &completion));
72 completion.Wait();
73 }
74
75 void CreateArrowFromArrow(Arrow** arrow, const Arrow* other) {
76 WaitableEvent completion(true, false);
77 task_runner()->PostTask(
78 FROM_HERE, base::Bind(&BackgroundThread::DoCreateArrowFromArrow, arrow,
79 other, &completion));
80 completion.Wait();
81 }
82
83 void DeleteTarget(Target* object) {
84 WaitableEvent completion(true, false);
85 task_runner()->PostTask(
86 FROM_HERE,
87 base::Bind(&BackgroundThread::DoDeleteTarget, object, &completion));
88 completion.Wait();
89 }
90
91 void CopyAndAssignArrow(Arrow* object) {
92 WaitableEvent completion(true, false);
93 task_runner()->PostTask(
94 FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrow, object,
95 &completion));
96 completion.Wait();
97 }
98
99 void CopyAndAssignArrowBase(Arrow* object) {
100 WaitableEvent completion(true, false);
101 task_runner()->PostTask(
102 FROM_HERE, base::Bind(&BackgroundThread::DoCopyAndAssignArrowBase,
103 object, &completion));
104 completion.Wait();
105 }
106
107 void DeleteArrow(Arrow* object) {
108 WaitableEvent completion(true, false);
109 task_runner()->PostTask(
110 FROM_HERE,
111 base::Bind(&BackgroundThread::DoDeleteArrow, object, &completion));
112 completion.Wait();
113 }
114
115 Target* DeRef(const Arrow* arrow) {
116 WaitableEvent completion(true, false);
117 Target* result = NULL;
118 task_runner()->PostTask(FROM_HERE, base::Bind(&BackgroundThread::DoDeRef,
119 arrow, &result, &completion));
120 completion.Wait();
121 return result;
122 }
123
124 protected:
125 static void DoCreateArrowFromArrow(Arrow** arrow,
126 const Arrow* other,
127 WaitableEvent* completion) {
128 *arrow = new Arrow;
129 **arrow = *other;
130 completion->Signal();
131 }
132
133 static void DoCreateArrowFromTarget(Arrow** arrow,
134 Target* target,
135 WaitableEvent* completion) {
136 *arrow = new Arrow;
137 (*arrow)->target = target->AsWeakPtr();
138 completion->Signal();
139 }
140
141 static void DoDeRef(const Arrow* arrow,
142 Target** result,
143 WaitableEvent* completion) {
144 *result = arrow->target.get();
145 completion->Signal();
146 }
147
148 static void DoDeleteTarget(Target* object, WaitableEvent* completion) {
149 delete object;
150 completion->Signal();
151 }
152
153 static void DoCopyAndAssignArrow(Arrow* object, WaitableEvent* completion) {
154 // Copy constructor.
155 Arrow a = *object;
156 // Assignment operator.
157 *object = a;
158 completion->Signal();
159 }
160
161 static void DoCopyAndAssignArrowBase(
162 Arrow* object,
163 WaitableEvent* completion) {
164 // Copy constructor.
165 WeakPtr<TargetBase> b = object->target;
166 // Assignment operator.
167 WeakPtr<TargetBase> c;
168 c = object->target;
169 completion->Signal();
170 }
171
172 static void DoDeleteArrow(Arrow* object, WaitableEvent* completion) {
173 delete object;
174 completion->Signal();
175 }
176 };
177
178 } // namespace
179
180 TEST(WeakPtrFactoryTest, Basic) {
181 int data;
182 WeakPtrFactory<int> factory(&data);
183 WeakPtr<int> ptr = factory.GetWeakPtr();
184 EXPECT_EQ(&data, ptr.get());
185 }
186
187 TEST(WeakPtrFactoryTest, Comparison) {
188 int data;
189 WeakPtrFactory<int> factory(&data);
190 WeakPtr<int> ptr = factory.GetWeakPtr();
191 WeakPtr<int> ptr2 = ptr;
192 EXPECT_EQ(ptr.get(), ptr2.get());
193 }
194
195 TEST(WeakPtrFactoryTest, OutOfScope) {
196 WeakPtr<int> ptr;
197 EXPECT_EQ(NULL, ptr.get());
198 {
199 int data;
200 WeakPtrFactory<int> factory(&data);
201 ptr = factory.GetWeakPtr();
202 }
203 EXPECT_EQ(NULL, ptr.get());
204 }
205
206 TEST(WeakPtrFactoryTest, Multiple) {
207 WeakPtr<int> a, b;
208 {
209 int data;
210 WeakPtrFactory<int> factory(&data);
211 a = factory.GetWeakPtr();
212 b = factory.GetWeakPtr();
213 EXPECT_EQ(&data, a.get());
214 EXPECT_EQ(&data, b.get());
215 }
216 EXPECT_EQ(NULL, a.get());
217 EXPECT_EQ(NULL, b.get());
218 }
219
220 TEST(WeakPtrFactoryTest, MultipleStaged) {
221 WeakPtr<int> a;
222 {
223 int data;
224 WeakPtrFactory<int> factory(&data);
225 a = factory.GetWeakPtr();
226 {
227 WeakPtr<int> b = factory.GetWeakPtr();
228 }
229 EXPECT_TRUE(NULL != a.get());
230 }
231 EXPECT_EQ(NULL, a.get());
232 }
233
234 TEST(WeakPtrFactoryTest, Dereference) {
235 Base data;
236 data.member = "123456";
237 WeakPtrFactory<Base> factory(&data);
238 WeakPtr<Base> ptr = factory.GetWeakPtr();
239 EXPECT_EQ(&data, ptr.get());
240 EXPECT_EQ(data.member, (*ptr).member);
241 EXPECT_EQ(data.member, ptr->member);
242 }
243
244 TEST(WeakPtrFactoryTest, UpCast) {
245 Derived data;
246 WeakPtrFactory<Derived> factory(&data);
247 WeakPtr<Base> ptr = factory.GetWeakPtr();
248 ptr = factory.GetWeakPtr();
249 EXPECT_EQ(ptr.get(), &data);
250 }
251
252 TEST(WeakPtrTest, SupportsWeakPtr) {
253 Target target;
254 WeakPtr<Target> ptr = target.AsWeakPtr();
255 EXPECT_EQ(&target, ptr.get());
256 }
257
258 TEST(WeakPtrTest, DerivedTarget) {
259 DerivedTarget target;
260 WeakPtr<DerivedTarget> ptr = AsWeakPtr(&target);
261 EXPECT_EQ(&target, ptr.get());
262 }
263
264 TEST(WeakPtrTest, InvalidateWeakPtrs) {
265 int data;
266 WeakPtrFactory<int> factory(&data);
267 WeakPtr<int> ptr = factory.GetWeakPtr();
268 EXPECT_EQ(&data, ptr.get());
269 EXPECT_TRUE(factory.HasWeakPtrs());
270 factory.InvalidateWeakPtrs();
271 EXPECT_EQ(NULL, ptr.get());
272 EXPECT_FALSE(factory.HasWeakPtrs());
273
274 // Test that the factory can create new weak pointers after a
275 // InvalidateWeakPtrs call, and they remain valid until the next
276 // InvalidateWeakPtrs call.
277 WeakPtr<int> ptr2 = factory.GetWeakPtr();
278 EXPECT_EQ(&data, ptr2.get());
279 EXPECT_TRUE(factory.HasWeakPtrs());
280 factory.InvalidateWeakPtrs();
281 EXPECT_EQ(NULL, ptr2.get());
282 EXPECT_FALSE(factory.HasWeakPtrs());
283 }
284
285 TEST(WeakPtrTest, HasWeakPtrs) {
286 int data;
287 WeakPtrFactory<int> factory(&data);
288 {
289 WeakPtr<int> ptr = factory.GetWeakPtr();
290 EXPECT_TRUE(factory.HasWeakPtrs());
291 }
292 EXPECT_FALSE(factory.HasWeakPtrs());
293 }
294
295 TEST(WeakPtrTest, ObjectAndWeakPtrOnDifferentThreads) {
296 // Test that it is OK to create an object that supports WeakPtr on one thread,
297 // but use it on another. This tests that we do not trip runtime checks that
298 // ensure that a WeakPtr is not used by multiple threads.
299 scoped_ptr<Target> target(OffThreadObjectCreator<Target>::NewObject());
300 WeakPtr<Target> weak_ptr = target->AsWeakPtr();
301 EXPECT_EQ(target.get(), weak_ptr.get());
302 }
303
304 TEST(WeakPtrTest, WeakPtrInitiateAndUseOnDifferentThreads) {
305 // Test that it is OK to create an object that has a WeakPtr member on one
306 // thread, but use it on another. This tests that we do not trip runtime
307 // checks that ensure that a WeakPtr is not used by multiple threads.
308 scoped_ptr<Arrow> arrow(OffThreadObjectCreator<Arrow>::NewObject());
309 Target target;
310 arrow->target = target.AsWeakPtr();
311 EXPECT_EQ(&target, arrow->target.get());
312 }
313
314 TEST(WeakPtrTest, MoveOwnershipImplicitly) {
315 // Move object ownership to another thread by releasing all weak pointers
316 // on the original thread first, and then establish WeakPtr on a different
317 // thread.
318 BackgroundThread background;
319 background.Start();
320
321 Target* target = new Target();
322 {
323 WeakPtr<Target> weak_ptr = target->AsWeakPtr();
324 // Main thread deletes the WeakPtr, then the thread ownership of the
325 // object can be implicitly moved.
326 }
327 Arrow* arrow;
328
329 // Background thread creates WeakPtr(and implicitly owns the object).
330 background.CreateArrowFromTarget(&arrow, target);
331 EXPECT_EQ(background.DeRef(arrow), target);
332
333 {
334 // Main thread creates another WeakPtr, but this does not trigger implicitly
335 // thread ownership move.
336 Arrow arrow;
337 arrow.target = target->AsWeakPtr();
338
339 // The new WeakPtr is owned by background thread.
340 EXPECT_EQ(target, background.DeRef(&arrow));
341 }
342
343 // Target can only be deleted on background thread.
344 background.DeleteTarget(target);
345 background.DeleteArrow(arrow);
346 }
347
348 TEST(WeakPtrTest, MoveOwnershipOfUnreferencedObject) {
349 BackgroundThread background;
350 background.Start();
351
352 Arrow* arrow;
353 {
354 Target target;
355 // Background thread creates WeakPtr.
356 background.CreateArrowFromTarget(&arrow, &target);
357
358 // Bind to background thread.
359 EXPECT_EQ(&target, background.DeRef(arrow));
360
361 // Release the only WeakPtr.
362 arrow->target.reset();
363
364 // Now we should be able to create a new reference from this thread.
365 arrow->target = target.AsWeakPtr();
366
367 // Re-bind to main thread.
368 EXPECT_EQ(&target, arrow->target.get());
369
370 // And the main thread can now delete the target.
371 }
372
373 delete arrow;
374 }
375
376 TEST(WeakPtrTest, MoveOwnershipAfterInvalidate) {
377 BackgroundThread background;
378 background.Start();
379
380 Arrow arrow;
381 scoped_ptr<TargetWithFactory> target(new TargetWithFactory);
382
383 // Bind to main thread.
384 arrow.target = target->factory.GetWeakPtr();
385 EXPECT_EQ(target.get(), arrow.target.get());
386
387 target->factory.InvalidateWeakPtrs();
388 EXPECT_EQ(NULL, arrow.target.get());
389
390 arrow.target = target->factory.GetWeakPtr();
391 // Re-bind to background thread.
392 EXPECT_EQ(target.get(), background.DeRef(&arrow));
393
394 // And the background thread can now delete the target.
395 background.DeleteTarget(target.release());
396 }
397
398 TEST(WeakPtrTest, MainThreadRefOutlivesBackgroundThreadRef) {
399 // Originating thread has a WeakPtr that outlives others.
400 // - Main thread creates a WeakPtr
401 // - Background thread creates a WeakPtr copy from the one in main thread
402 // - Destruct the WeakPtr on background thread
403 // - Destruct the WeakPtr on main thread
404 BackgroundThread background;
405 background.Start();
406
407 Target target;
408 Arrow arrow;
409 arrow.target = target.AsWeakPtr();
410
411 Arrow* arrow_copy;
412 background.CreateArrowFromArrow(&arrow_copy, &arrow);
413 EXPECT_EQ(arrow_copy->target.get(), &target);
414 background.DeleteArrow(arrow_copy);
415 }
416
417 TEST(WeakPtrTest, BackgroundThreadRefOutlivesMainThreadRef) {
418 // Originating thread drops all references before another thread.
419 // - Main thread creates a WeakPtr and passes copy to background thread
420 // - Destruct the pointer on main thread
421 // - Destruct the pointer on background thread
422 BackgroundThread background;
423 background.Start();
424
425 Target target;
426 Arrow* arrow_copy;
427 {
428 Arrow arrow;
429 arrow.target = target.AsWeakPtr();
430 background.CreateArrowFromArrow(&arrow_copy, &arrow);
431 }
432 EXPECT_EQ(arrow_copy->target.get(), &target);
433 background.DeleteArrow(arrow_copy);
434 }
435
436 TEST(WeakPtrTest, OwnerThreadDeletesObject) {
437 // Originating thread invalidates WeakPtrs while its held by other thread.
438 // - Main thread creates WeakPtr and passes Copy to background thread
439 // - Object gets destroyed on main thread
440 // (invalidates WeakPtr on background thread)
441 // - WeakPtr gets destroyed on Thread B
442 BackgroundThread background;
443 background.Start();
444 Arrow* arrow_copy;
445 {
446 Target target;
447 Arrow arrow;
448 arrow.target = target.AsWeakPtr();
449 background.CreateArrowFromArrow(&arrow_copy, &arrow);
450 }
451 EXPECT_EQ(NULL, arrow_copy->target.get());
452 background.DeleteArrow(arrow_copy);
453 }
454
455 TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtr) {
456 // Main thread creates a Target object.
457 Target target;
458 // Main thread creates an arrow referencing the Target.
459 Arrow *arrow = new Arrow();
460 arrow->target = target.AsWeakPtr();
461
462 // Background can copy and assign arrow (as well as the WeakPtr inside).
463 BackgroundThread background;
464 background.Start();
465 background.CopyAndAssignArrow(arrow);
466 background.DeleteArrow(arrow);
467 }
468
469 TEST(WeakPtrTest, NonOwnerThreadCanCopyAndAssignWeakPtrBase) {
470 // Main thread creates a Target object.
471 Target target;
472 // Main thread creates an arrow referencing the Target.
473 Arrow *arrow = new Arrow();
474 arrow->target = target.AsWeakPtr();
475
476 // Background can copy and assign arrow's WeakPtr to a base class WeakPtr.
477 BackgroundThread background;
478 background.Start();
479 background.CopyAndAssignArrowBase(arrow);
480 background.DeleteArrow(arrow);
481 }
482
483 TEST(WeakPtrTest, NonOwnerThreadCanDeleteWeakPtr) {
484 // Main thread creates a Target object.
485 Target target;
486 // Main thread creates an arrow referencing the Target.
487 Arrow* arrow = new Arrow();
488 arrow->target = target.AsWeakPtr();
489
490 // Background can delete arrow (as well as the WeakPtr inside).
491 BackgroundThread background;
492 background.Start();
493 background.DeleteArrow(arrow);
494 }
495
496 #if (!defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)) && GTEST_HAS_DEATH_TEST
497
498 TEST(WeakPtrDeathTest, WeakPtrCopyDoesNotChangeThreadBinding) {
499 // The default style "fast" does not support multi-threaded tests
500 // (introduces deadlock on Linux).
501 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
502
503 BackgroundThread background;
504 background.Start();
505
506 // Main thread creates a Target object.
507 Target target;
508 // Main thread creates an arrow referencing the Target.
509 Arrow arrow;
510 arrow.target = target.AsWeakPtr();
511
512 // Background copies the WeakPtr.
513 Arrow* arrow_copy;
514 background.CreateArrowFromArrow(&arrow_copy, &arrow);
515
516 // The copy is still bound to main thread so I can deref.
517 EXPECT_EQ(arrow.target.get(), arrow_copy->target.get());
518
519 // Although background thread created the copy, it can not deref the copied
520 // WeakPtr.
521 ASSERT_DEATH(background.DeRef(arrow_copy), "");
522
523 background.DeleteArrow(arrow_copy);
524 }
525
526 TEST(WeakPtrDeathTest, NonOwnerThreadDereferencesWeakPtrAfterReference) {
527 // The default style "fast" does not support multi-threaded tests
528 // (introduces deadlock on Linux).
529 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
530
531 // Main thread creates a Target object.
532 Target target;
533
534 // Main thread creates an arrow referencing the Target (so target's
535 // thread ownership can not be implicitly moved).
536 Arrow arrow;
537 arrow.target = target.AsWeakPtr();
538 arrow.target.get();
539
540 // Background thread tries to deref target, which violates thread ownership.
541 BackgroundThread background;
542 background.Start();
543 ASSERT_DEATH(background.DeRef(&arrow), "");
544 }
545
546 TEST(WeakPtrDeathTest, NonOwnerThreadDeletesWeakPtrAfterReference) {
547 // The default style "fast" does not support multi-threaded tests
548 // (introduces deadlock on Linux).
549 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
550
551 scoped_ptr<Target> target(new Target());
552
553 // Main thread creates an arrow referencing the Target.
554 Arrow arrow;
555 arrow.target = target->AsWeakPtr();
556
557 // Background thread tries to deref target, binding it to the thread.
558 BackgroundThread background;
559 background.Start();
560 background.DeRef(&arrow);
561
562 // Main thread deletes Target, violating thread binding.
563 ASSERT_DEATH(target.reset(), "");
564
565 // |target.reset()| died so |target| still holds the object, so we
566 // must pass it to the background thread to teardown.
567 background.DeleteTarget(target.release());
568 }
569
570 TEST(WeakPtrDeathTest, NonOwnerThreadDeletesObjectAfterReference) {
571 // The default style "fast" does not support multi-threaded tests
572 // (introduces deadlock on Linux).
573 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
574
575 scoped_ptr<Target> target(new Target());
576
577 // Main thread creates an arrow referencing the Target, and references it, so
578 // that it becomes bound to the thread.
579 Arrow arrow;
580 arrow.target = target->AsWeakPtr();
581 arrow.target.get();
582
583 // Background thread tries to delete target, volating thread binding.
584 BackgroundThread background;
585 background.Start();
586 ASSERT_DEATH(background.DeleteTarget(target.release()), "");
587 }
588
589 TEST(WeakPtrDeathTest, NonOwnerThreadReferencesObjectAfterDeletion) {
590 // The default style "fast" does not support multi-threaded tests
591 // (introduces deadlock on Linux).
592 ::testing::FLAGS_gtest_death_test_style = "threadsafe";
593
594 scoped_ptr<Target> target(new Target());
595
596 // Main thread creates an arrow referencing the Target.
597 Arrow arrow;
598 arrow.target = target->AsWeakPtr();
599
600 // Background thread tries to delete target, binding the object to the thread.
601 BackgroundThread background;
602 background.Start();
603 background.DeleteTarget(target.release());
604
605 // Main thread attempts to dereference the target, violating thread binding.
606 ASSERT_DEATH(arrow.target.get(), "");
607 }
608
609 #endif
610
611 } // namespace base
OLDNEW
« no previous file with comments | « base/memory/weak_ptr.cc ('k') | base/memory/weak_ptr_unittest.nc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698