Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/observer_list.h" | 5 #include "base/observer_list.h" |
| 6 #include "base/observer_list_threadsafe.h" | |
|
gab
2017/01/12 16:24:06
Keep it up here I'd say (though it's weird to conf
fdoray
2017/01/12 17:17:57
Done.
| |
| 7 | 6 |
| 7 #include <utility> | |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/bind.h" | |
| 10 #include "base/compiler_specific.h" | 11 #include "base/compiler_specific.h" |
| 11 #include "base/location.h" | 12 #include "base/location.h" |
| 12 #include "base/memory/weak_ptr.h" | 13 #include "base/memory/weak_ptr.h" |
| 14 #include "base/observer_list_threadsafe.h" | |
| 13 #include "base/run_loop.h" | 15 #include "base/run_loop.h" |
| 16 #include "base/sequenced_task_runner.h" | |
| 14 #include "base/single_thread_task_runner.h" | 17 #include "base/single_thread_task_runner.h" |
| 18 #include "base/task_scheduler/post_task.h" | |
| 19 #include "base/test/scoped_task_scheduler.h" | |
| 15 #include "base/threading/platform_thread.h" | 20 #include "base/threading/platform_thread.h" |
| 16 #include "testing/gtest/include/gtest/gtest.h" | 21 #include "testing/gtest/include/gtest/gtest.h" |
| 17 | 22 |
| 18 namespace base { | 23 namespace base { |
| 19 namespace { | 24 namespace { |
| 20 | 25 |
| 21 class Foo { | 26 class Foo { |
| 22 public: | 27 public: |
| 23 virtual void Observe(int x) = 0; | 28 virtual void Observe(int x) = 0; |
| 24 virtual ~Foo() {} | 29 virtual ~Foo() {} |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 322 // Should also do nothing. | 327 // Should also do nothing. |
| 323 observer_list->RemoveObserver(&b); | 328 observer_list->RemoveObserver(&b); |
| 324 | 329 |
| 325 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); | 330 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); |
| 326 RunLoop().RunUntilIdle(); | 331 RunLoop().RunUntilIdle(); |
| 327 | 332 |
| 328 EXPECT_EQ(10, a.total); | 333 EXPECT_EQ(10, a.total); |
| 329 EXPECT_EQ(0, b.total); | 334 EXPECT_EQ(0, b.total); |
| 330 } | 335 } |
| 331 | 336 |
| 332 TEST(ObserverListThreadSafeTest, WithoutMessageLoop) { | 337 TEST(ObserverListThreadSafeTest, WithoutSequence) { |
| 333 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( | 338 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( |
| 334 new ObserverListThreadSafe<Foo>); | 339 new ObserverListThreadSafe<Foo>); |
| 335 | 340 |
| 336 Adder a(1), b(1), c(1); | 341 Adder a(1), b(1), c(1); |
| 337 | 342 |
| 338 // No MessageLoop, so these should not be added. | 343 // No sequence, so these should not be added. |
| 339 observer_list->AddObserver(&a); | 344 observer_list->AddObserver(&a); |
| 340 observer_list->AddObserver(&b); | 345 observer_list->AddObserver(&b); |
| 341 | 346 |
| 342 { | 347 { |
| 343 // Add c when there's a loop. | 348 // Add c when there's a sequence. |
| 344 MessageLoop loop; | 349 MessageLoop loop; |
| 345 observer_list->AddObserver(&c); | 350 observer_list->AddObserver(&c); |
| 346 | 351 |
| 347 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); | 352 observer_list->Notify(FROM_HERE, &Foo::Observe, 10); |
| 348 RunLoop().RunUntilIdle(); | 353 RunLoop().RunUntilIdle(); |
| 349 | 354 |
| 350 EXPECT_EQ(0, a.total); | 355 EXPECT_EQ(0, a.total); |
| 351 EXPECT_EQ(0, b.total); | 356 EXPECT_EQ(0, b.total); |
| 352 EXPECT_EQ(10, c.total); | 357 EXPECT_EQ(10, c.total); |
| 353 | 358 |
| 354 // Now add a when there's a loop. | 359 // Now add a when there's a sequence. |
| 355 observer_list->AddObserver(&a); | 360 observer_list->AddObserver(&a); |
| 356 | 361 |
| 357 // Remove c when there's a loop. | 362 // Remove c when there's a sequence. |
| 358 observer_list->RemoveObserver(&c); | 363 observer_list->RemoveObserver(&c); |
| 359 | 364 |
| 360 // Notify again. | 365 // Notify again. |
| 361 observer_list->Notify(FROM_HERE, &Foo::Observe, 20); | 366 observer_list->Notify(FROM_HERE, &Foo::Observe, 20); |
| 362 RunLoop().RunUntilIdle(); | 367 RunLoop().RunUntilIdle(); |
| 363 | 368 |
| 364 EXPECT_EQ(20, a.total); | 369 EXPECT_EQ(20, a.total); |
| 365 EXPECT_EQ(0, b.total); | 370 EXPECT_EQ(0, b.total); |
| 366 EXPECT_EQ(10, c.total); | 371 EXPECT_EQ(10, c.total); |
| 367 } | 372 } |
| 368 | 373 |
| 369 // Removing should always succeed with or without a loop. | 374 // Removing should always succeed with or without a sequence. |
| 370 observer_list->RemoveObserver(&a); | 375 observer_list->RemoveObserver(&a); |
| 371 | 376 |
| 372 // Notifying should not fail but should also be a no-op. | 377 // Notifying should not fail but should also be a no-op. |
| 373 MessageLoop loop; | 378 MessageLoop loop; |
| 374 observer_list->AddObserver(&b); | 379 observer_list->AddObserver(&b); |
| 375 observer_list->Notify(FROM_HERE, &Foo::Observe, 30); | 380 observer_list->Notify(FROM_HERE, &Foo::Observe, 30); |
| 376 RunLoop().RunUntilIdle(); | 381 RunLoop().RunUntilIdle(); |
| 377 | 382 |
| 378 EXPECT_EQ(20, a.total); | 383 EXPECT_EQ(20, a.total); |
| 379 EXPECT_EQ(30, b.total); | 384 EXPECT_EQ(30, b.total); |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 484 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( | 489 scoped_refptr<ObserverListThreadSafe<Foo> > observer_list( |
| 485 new ObserverListThreadSafe<Foo>); | 490 new ObserverListThreadSafe<Foo>); |
| 486 | 491 |
| 487 Adder a(1); | 492 Adder a(1); |
| 488 observer_list->AddObserver(&a); | 493 observer_list->AddObserver(&a); |
| 489 delete loop; | 494 delete loop; |
| 490 // Test passes if we don't crash here. | 495 // Test passes if we don't crash here. |
| 491 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); | 496 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); |
| 492 } | 497 } |
| 493 | 498 |
| 499 namespace { | |
| 500 | |
| 501 class SequenceVerificationObserver : public Foo { | |
| 502 public: | |
| 503 explicit SequenceVerificationObserver( | |
| 504 scoped_refptr<SequencedTaskRunner> task_runner) | |
| 505 : task_runner_(std::move(task_runner)) {} | |
| 506 ~SequenceVerificationObserver() override = default; | |
| 507 | |
| 508 void Observe(int x) override { | |
| 509 called_on_valid_sequence_ = task_runner_->RunsTasksOnCurrentThread(); | |
| 510 } | |
| 511 | |
| 512 bool called_on_valid_sequence() const { return called_on_valid_sequence_; } | |
| 513 | |
| 514 private: | |
| 515 const scoped_refptr<SequencedTaskRunner> task_runner_; | |
| 516 bool called_on_valid_sequence_ = false; | |
| 517 | |
| 518 DISALLOW_COPY_AND_ASSIGN(SequenceVerificationObserver); | |
| 519 }; | |
| 520 | |
| 521 } // namespace | |
| 522 | |
| 523 // Verify that observers are notified on the correct sequence. | |
| 524 TEST(ObserverListThreadSafeTest, NotificationOnValidSequence) { | |
| 525 using ObserverListType = ObserverListThreadSafe<Foo>; | |
| 526 | |
| 527 test::ScopedTaskScheduler scoped_task_scheduler; | |
| 528 | |
| 529 auto task_runner_1 = CreateSequencedTaskRunnerWithTraits(TaskTraits()); | |
| 530 auto task_runner_2 = CreateSequencedTaskRunnerWithTraits(TaskTraits()); | |
| 531 | |
| 532 auto observer_list = make_scoped_refptr(new ObserverListType()); | |
| 533 | |
| 534 SequenceVerificationObserver observer_1(task_runner_1); | |
| 535 SequenceVerificationObserver observer_2(task_runner_2); | |
| 536 | |
| 537 task_runner_1->PostTask(FROM_HERE, | |
| 538 Bind(&ObserverListType::AddObserver, observer_list, | |
| 539 Unretained(&observer_1))); | |
| 540 task_runner_2->PostTask(FROM_HERE, | |
| 541 Bind(&ObserverListType::AddObserver, observer_list, | |
| 542 Unretained(&observer_2))); | |
| 543 | |
| 544 RunLoop().RunUntilIdle(); | |
| 545 | |
| 546 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); | |
| 547 | |
| 548 RunLoop().RunUntilIdle(); | |
| 549 | |
| 550 EXPECT_TRUE(observer_1.called_on_valid_sequence()); | |
| 551 EXPECT_TRUE(observer_2.called_on_valid_sequence()); | |
| 552 } | |
| 553 | |
| 554 // Verify that when an observer is added to a NOTIFY_ALL ObserverListThreadSafe | |
| 555 // from a notification, it is itself notified. | |
| 556 TEST(ObserverListThreadSafeTest, AddObserverFromNotificationNotifyAll) { | |
| 557 using ObserverListType = ObserverListThreadSafe<Foo>; | |
|
gab
2017/01/12 16:24:06
Don't think the using is worth it for two sites, i
fdoray
2017/01/12 17:17:57
Done.
| |
| 558 | |
| 559 MessageLoop message_loop; | |
| 560 auto observer_list = make_scoped_refptr(new ObserverListType()); | |
| 561 | |
| 562 Adder observer_added_from_notification(1); | |
| 563 | |
| 564 AddInObserve<ObserverListType> initial_observer(observer_list.get()); | |
| 565 initial_observer.SetToAdd(&observer_added_from_notification); | |
| 566 observer_list->AddObserver(&initial_observer); | |
| 567 | |
| 568 observer_list->Notify(FROM_HERE, &Foo::Observe, 1); | |
| 569 | |
| 570 RunLoop().RunUntilIdle(); | |
| 571 | |
| 572 EXPECT_EQ(1, observer_added_from_notification.GetValue()); | |
| 573 } | |
| 574 | |
| 494 TEST(ObserverListTest, Existing) { | 575 TEST(ObserverListTest, Existing) { |
| 495 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY); | 576 ObserverList<Foo> observer_list(ObserverList<Foo>::NOTIFY_EXISTING_ONLY); |
| 496 Adder a(1); | 577 Adder a(1); |
| 497 AddInObserve<ObserverList<Foo> > b(&observer_list); | 578 AddInObserve<ObserverList<Foo> > b(&observer_list); |
| 498 Adder c(1); | 579 Adder c(1); |
| 499 b.SetToAdd(&c); | 580 b.SetToAdd(&c); |
| 500 | 581 |
| 501 observer_list.AddObserver(&a); | 582 observer_list.AddObserver(&a); |
| 502 observer_list.AddObserver(&b); | 583 observer_list.AddObserver(&b); |
| 503 | 584 |
| (...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 926 // However, the first Observe() call will add a second observer: at this | 1007 // However, the first Observe() call will add a second observer: at this |
| 927 // point, it != observer_list.end() should be true, and Observe() should be | 1008 // point, it != observer_list.end() should be true, and Observe() should be |
| 928 // called on the newly added observer on the next iteration of the loop. | 1009 // called on the newly added observer on the next iteration of the loop. |
| 929 observer.Observe(10); | 1010 observer.Observe(10); |
| 930 } | 1011 } |
| 931 | 1012 |
| 932 EXPECT_EQ(-10, b.total); | 1013 EXPECT_EQ(-10, b.total); |
| 933 } | 1014 } |
| 934 | 1015 |
| 935 } // namespace base | 1016 } // namespace base |
| OLD | NEW |