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

Unified Diff: ui/compositor/callback_layer_animation_observer_unittest.cc

Issue 1369393002: Added a CallbackLayerAnimationObserver. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed concerns from patch set 8. Created 5 years, 2 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/compositor/callback_layer_animation_observer.cc ('k') | ui/compositor/compositor.gyp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/compositor/callback_layer_animation_observer_unittest.cc
diff --git a/ui/compositor/callback_layer_animation_observer_unittest.cc b/ui/compositor/callback_layer_animation_observer_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..b5d708fb39ac7b2a807f57719d7a91fd0e7c87dd
--- /dev/null
+++ b/ui/compositor/callback_layer_animation_observer_unittest.cc
@@ -0,0 +1,522 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/compositor/callback_layer_animation_observer.h"
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/scoped_vector.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/compositor/layer_animation_sequence.h"
+#include "ui/compositor/test/layer_animation_observer_test_api.h"
+
+namespace ui {
+namespace test {
+
+// Simple class that tracks whether callbacks were invoked and when.
+class TestCallbacks {
+ public:
+ TestCallbacks();
+ virtual ~TestCallbacks();
+
+ void ResetCallbackObservations();
+
+ void set_should_delete_observer_on_animations_ended(
+ bool should_delete_observer_on_animations_ended) {
+ should_delete_observer_on_animations_ended_ =
+ should_delete_observer_on_animations_ended;
+ }
+
+ bool animations_started() const { return animations_started_; }
+
+ bool animations_ended() const { return animations_ended_; }
+
+ virtual void AnimationsStarted(const CallbackLayerAnimationObserver&);
+
+ virtual bool AnimationsEnded(const CallbackLayerAnimationObserver&);
+
+ testing::AssertionResult StartedEpochIsBeforeEndedEpoch();
+
+ private:
+ // Monotonic counter that tracks the next time snapshot.
+ int next_epoch_ = 0;
+
+ // Is true when AnimationsStarted() has been called.
+ bool animations_started_ = false;
+
+ // Relative time snapshot of when AnimationsStarted() was last called.
+ int animations_started_epoch_ = -1;
+
+ // Is true when AnimationsEnded() has been called.
+ bool animations_ended_ = false;
+
+ // Relative time snapshot of when AnimationsEnded() was last called.
+ int animations_ended_epoch_ = -1;
+
+ // The return value for AnimationsEnded().
+ bool should_delete_observer_on_animations_ended_ = false;
+
+ DISALLOW_COPY_AND_ASSIGN(TestCallbacks);
+};
+
+TestCallbacks::TestCallbacks() {}
+
+TestCallbacks::~TestCallbacks() {}
+
+void TestCallbacks::ResetCallbackObservations() {
+ next_epoch_ = 0;
+ animations_started_ = false;
+ animations_started_epoch_ = -1;
+ animations_ended_ = false;
+ animations_ended_epoch_ = -1;
+ should_delete_observer_on_animations_ended_ = false;
+}
+
+void TestCallbacks::AnimationsStarted(const CallbackLayerAnimationObserver&) {
+ animations_started_ = true;
+ animations_started_epoch_ = next_epoch_++;
+}
+
+bool TestCallbacks::AnimationsEnded(const CallbackLayerAnimationObserver&) {
+ animations_ended_ = true;
+ animations_ended_epoch_ = next_epoch_++;
+ return should_delete_observer_on_animations_ended_;
+}
+
+testing::AssertionResult TestCallbacks::StartedEpochIsBeforeEndedEpoch() {
+ if (animations_started_epoch_ < animations_ended_epoch_) {
+ return testing::AssertionSuccess();
+ } else {
+ return testing::AssertionFailure()
+ << "The started epoch=" << animations_started_epoch_
+ << " is NOT before the ended epoch=" << animations_ended_epoch_;
+ }
+}
+
+// A child of TestCallbacks that can explicitly delete a
+// CallbackLayerAnimationObserver in the AnimationsStarted() or
+// AnimationsEnded() callback.
+class TestCallbacksThatExplicitlyDeletesObserver : public TestCallbacks {
+ public:
+ TestCallbacksThatExplicitlyDeletesObserver();
+
+ void set_observer_to_delete_in_animation_started(
+ CallbackLayerAnimationObserver* observer) {
+ observer_to_delete_in_animation_started_ = observer;
+ }
+
+ void set_observer_to_delete_in_animation_ended(
+ CallbackLayerAnimationObserver* observer) {
+ observer_to_delete_in_animation_ended_ = observer;
+ }
+
+ // TestCallbacks:
+ void AnimationsStarted(
+ const CallbackLayerAnimationObserver& observer) override;
+ bool AnimationsEnded(const CallbackLayerAnimationObserver& observer) override;
+
+ private:
+ // The observer to delete, if non-NULL, in AnimationsStarted().
+ CallbackLayerAnimationObserver* observer_to_delete_in_animation_started_ =
+ nullptr;
+
+ // The observer to delete, if non-NULL, in AnimationsEnded().
+ CallbackLayerAnimationObserver* observer_to_delete_in_animation_ended_ =
+ nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(TestCallbacksThatExplicitlyDeletesObserver);
+};
+
+TestCallbacksThatExplicitlyDeletesObserver::
+ TestCallbacksThatExplicitlyDeletesObserver() {}
+
+void TestCallbacksThatExplicitlyDeletesObserver::AnimationsStarted(
+ const CallbackLayerAnimationObserver& observer) {
+ if (observer_to_delete_in_animation_started_)
+ delete observer_to_delete_in_animation_started_;
+ TestCallbacks::AnimationsStarted(observer);
+}
+
+bool TestCallbacksThatExplicitlyDeletesObserver::AnimationsEnded(
+ const CallbackLayerAnimationObserver& observer) {
+ if (observer_to_delete_in_animation_ended_)
+ delete observer_to_delete_in_animation_ended_;
+ return TestCallbacks::AnimationsEnded(observer);
+}
+
+// A test specific CallbackLayerAnimationObserver that will set a bool when
+// destroyed.
+class TestCallbackLayerAnimationObserver
+ : public CallbackLayerAnimationObserver {
+ public:
+ TestCallbackLayerAnimationObserver(
+ AnimationStartedCallback animation_started_callback,
+ AnimationEndedCallback animation_ended_callback,
+ bool* destroyed);
+ ~TestCallbackLayerAnimationObserver() override;
+
+ private:
+ bool* destroyed_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestCallbackLayerAnimationObserver);
+};
+
+TestCallbackLayerAnimationObserver::TestCallbackLayerAnimationObserver(
+ AnimationStartedCallback animation_started_callback,
+ AnimationEndedCallback animation_ended_callback,
+ bool* destroyed)
+ : CallbackLayerAnimationObserver(animation_started_callback,
+ animation_ended_callback),
+ destroyed_(destroyed) {
+ (*destroyed_) = false;
+}
+
+TestCallbackLayerAnimationObserver::~TestCallbackLayerAnimationObserver() {
+ (*destroyed_) = true;
+}
+
+class CallbackLayerAnimationObserverTest : public testing::Test {
+ public:
+ CallbackLayerAnimationObserverTest();
+ ~CallbackLayerAnimationObserverTest() override;
+
+ protected:
+ // Creates a LayerAnimationSequence. The lifetime of the sequence will be
+ // managed by this.
+ LayerAnimationSequence* CreateLayerAnimationSequence();
+
+ scoped_ptr<TestCallbacks> callbacks_;
+
+ scoped_ptr<CallbackLayerAnimationObserver> observer_;
+
+ scoped_ptr<LayerAnimationObserverTestApi> observer_test_api_;
+
+ // List of managaged sequences created by CreateLayerAnimationSequence() that
+ // need to be destroyed.
+ ScopedVector<LayerAnimationSequence> sequences_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CallbackLayerAnimationObserverTest);
+};
+
+CallbackLayerAnimationObserverTest::CallbackLayerAnimationObserverTest()
+ : callbacks_(new TestCallbacks()),
+ observer_(new CallbackLayerAnimationObserver(
+ base::Bind(&TestCallbacks::AnimationsStarted,
+ base::Unretained(callbacks_.get())),
+ base::Bind(&TestCallbacks::AnimationsEnded,
+ base::Unretained(callbacks_.get())))),
+ observer_test_api_(new LayerAnimationObserverTestApi(observer_.get())) {}
+
+CallbackLayerAnimationObserverTest::~CallbackLayerAnimationObserverTest() {
+ observer_test_api_.reset();
+ // The |observer_| will detach from all attached sequences upon destruction so
+ // we need to explicitly delete the |observer_| before the |sequences_| and
+ // |callbacks_|.
+ observer_.reset();
+}
+
+LayerAnimationSequence*
+CallbackLayerAnimationObserverTest::CreateLayerAnimationSequence() {
+ LayerAnimationSequence* sequence = new LayerAnimationSequence();
+ sequences_.push_back(sequence);
+ return sequence;
+}
+
+TEST_F(CallbackLayerAnimationObserverTest, VerifyInitialState) {
+ EXPECT_FALSE(observer_->active());
+ EXPECT_EQ(0, observer_->aborted_count());
+ EXPECT_EQ(0, observer_->successful_count());
+
+ EXPECT_FALSE(callbacks_->animations_started());
+ EXPECT_FALSE(callbacks_->animations_ended());
+}
+
+TEST(CallbackLayerAnimationObserverDestructionTest,
+ AnimationEndedReturnsFalse) {
+ TestCallbacks callbacks;
+ callbacks.set_should_delete_observer_on_animations_ended(false);
+
+ bool is_destroyed = false;
+
+ TestCallbackLayerAnimationObserver* observer =
+ new TestCallbackLayerAnimationObserver(
+ base::Bind(&TestCallbacks::AnimationsStarted,
+ base::Unretained(&callbacks)),
+ base::Bind(&TestCallbacks::AnimationsEnded,
+ base::Unretained(&callbacks)),
+ &is_destroyed);
+ observer->SetActive();
+
+ EXPECT_FALSE(is_destroyed);
+ delete observer;
+}
+
+TEST(CallbackLayerAnimationObserverDestructionTest, AnimationEndedReturnsTrue) {
+ TestCallbacks callbacks;
+ callbacks.set_should_delete_observer_on_animations_ended(true);
+
+ bool is_destroyed = false;
+
+ TestCallbackLayerAnimationObserver* observer =
+ new TestCallbackLayerAnimationObserver(
+ base::Bind(&TestCallbacks::AnimationsStarted,
+ base::Unretained(&callbacks)),
+ base::Bind(&TestCallbacks::AnimationsEnded,
+ base::Unretained(&callbacks)),
+ &is_destroyed);
+ observer->SetActive();
+
+ EXPECT_TRUE(is_destroyed);
+}
+
+// Verifies that the CallbackLayerAnimationObserver is robust to explicit
+// deletes caused as a side effect of calling the AnimationsStartedCallback()
+// when there are no animation sequences attached. This test also guards against
+// heap-use-after-free errors.
+TEST_F(
+ CallbackLayerAnimationObserverTest,
+ ExplicitlyDeleteObserverInAnimationStartedCallbackWithNoSequencesAttached) {
+ TestCallbacksThatExplicitlyDeletesObserver callbacks;
+ callbacks.set_should_delete_observer_on_animations_ended(true);
+
+ bool is_destroyed = false;
+
+ TestCallbackLayerAnimationObserver* observer =
+ new TestCallbackLayerAnimationObserver(
+ base::Bind(&TestCallbacks::AnimationsStarted,
+ base::Unretained(&callbacks)),
+ base::Bind(&TestCallbacks::AnimationsEnded,
+ base::Unretained(&callbacks)),
+ &is_destroyed);
+
+ callbacks.set_observer_to_delete_in_animation_started(observer);
+
+ observer->SetActive();
+
+ EXPECT_TRUE(is_destroyed);
+}
+
+// Verifies that the CallbackLayerAnimationObserver is robust to explicit
+// deletes caused as a side effect of calling the AnimationsStartedCallback()
+// when there are some animation sequences attached. This test also guards
+// against heap-use-after-free errors.
+TEST_F(
+ CallbackLayerAnimationObserverTest,
+ ExplicitlyDeleteObserverInAnimationStartedCallbackWithSomeSequencesAttached) {
+ LayerAnimationSequence* sequence_1 = CreateLayerAnimationSequence();
+ LayerAnimationSequence* sequence_2 = CreateLayerAnimationSequence();
+
+ TestCallbacksThatExplicitlyDeletesObserver callbacks;
+ callbacks.set_should_delete_observer_on_animations_ended(true);
+
+ bool is_destroyed = false;
+
+ TestCallbackLayerAnimationObserver* observer =
+ new TestCallbackLayerAnimationObserver(
+ base::Bind(&TestCallbacks::AnimationsStarted,
+ base::Unretained(&callbacks)),
+ base::Bind(&TestCallbacks::AnimationsEnded,
+ base::Unretained(&callbacks)),
+ &is_destroyed);
+
+ observer_test_api_->AttachedToSequence(sequence_1);
+ observer_test_api_->AttachedToSequence(sequence_2);
+ observer_->OnLayerAnimationStarted(sequence_1);
+ observer_->OnLayerAnimationStarted(sequence_2);
+
+ callbacks.set_observer_to_delete_in_animation_started(observer);
+
+ observer->SetActive();
+
+ EXPECT_TRUE(is_destroyed);
+}
+
+// Verifies that a 'true' return value for AnimationEndedCallback is ignored if
+// the CallbackLayerAnimationObserver is explicitly deleted as a side effect of
+// calling the AnimationEndedCallback. This test also guards against
+// heap-use-after-free errors.
+TEST_F(CallbackLayerAnimationObserverTest,
+ IgnoreTrueReturnValueForAnimationEndedCallbackIfExplicitlyDeleted) {
+ TestCallbacksThatExplicitlyDeletesObserver callbacks;
+ callbacks.set_should_delete_observer_on_animations_ended(true);
+
+ bool is_destroyed = false;
+
+ TestCallbackLayerAnimationObserver* observer =
+ new TestCallbackLayerAnimationObserver(
+ base::Bind(&TestCallbacks::AnimationsStarted,
+ base::Unretained(&callbacks)),
+ base::Bind(&TestCallbacks::AnimationsEnded,
+ base::Unretained(&callbacks)),
+ &is_destroyed);
+
+ callbacks.set_observer_to_delete_in_animation_ended(observer);
+
+ observer->SetActive();
+
+ EXPECT_TRUE(is_destroyed);
+}
+
+TEST_F(CallbackLayerAnimationObserverTest,
+ SetActiveWhenNoSequencesWereAttached) {
+ observer_->SetActive();
+
+ EXPECT_FALSE(observer_->active());
+ EXPECT_TRUE(callbacks_->animations_started());
+ EXPECT_TRUE(callbacks_->animations_ended());
+ EXPECT_TRUE(callbacks_->StartedEpochIsBeforeEndedEpoch());
+}
+
+TEST_F(CallbackLayerAnimationObserverTest,
+ SetActiveWhenAllSequencesAreAttachedButNoneWereStarted) {
+ LayerAnimationSequence* sequence_1 = CreateLayerAnimationSequence();
+ LayerAnimationSequence* sequence_2 = CreateLayerAnimationSequence();
+
+ observer_test_api_->AttachedToSequence(sequence_1);
+ observer_test_api_->AttachedToSequence(sequence_2);
+
+ observer_->SetActive();
+
+ EXPECT_TRUE(observer_->active());
+ EXPECT_FALSE(callbacks_->animations_started());
+ EXPECT_FALSE(callbacks_->animations_ended());
+}
+
+TEST_F(CallbackLayerAnimationObserverTest,
+ SetActiveWhenAllSequencesAreAttachedAndOnlySomeWereStarted) {
+ LayerAnimationSequence* sequence_1 = CreateLayerAnimationSequence();
+ LayerAnimationSequence* sequence_2 = CreateLayerAnimationSequence();
+
+ observer_test_api_->AttachedToSequence(sequence_1);
+ observer_test_api_->AttachedToSequence(sequence_2);
+ observer_->OnLayerAnimationStarted(sequence_1);
+
+ observer_->SetActive();
+
+ EXPECT_TRUE(observer_->active());
+ EXPECT_FALSE(callbacks_->animations_started());
+ EXPECT_FALSE(callbacks_->animations_ended());
+}
+
+TEST_F(CallbackLayerAnimationObserverTest,
+ SetActiveWhenAllSequencesAreAttachedAndOnlySomeWereCompleted) {
+ LayerAnimationSequence* sequence_1 = CreateLayerAnimationSequence();
+ LayerAnimationSequence* sequence_2 = CreateLayerAnimationSequence();
+
+ observer_test_api_->AttachedToSequence(sequence_1);
+ observer_test_api_->AttachedToSequence(sequence_2);
+ observer_->OnLayerAnimationStarted(sequence_1);
+ observer_->OnLayerAnimationEnded(sequence_1);
+
+ observer_->SetActive();
+
+ EXPECT_TRUE(observer_->active());
+ EXPECT_FALSE(callbacks_->animations_started());
+ EXPECT_FALSE(callbacks_->animations_ended());
+}
+
+TEST_F(CallbackLayerAnimationObserverTest,
+ SetActiveAfterAllSequencesWereStartedButNoneWereCompleted) {
+ LayerAnimationSequence* sequence_1 = CreateLayerAnimationSequence();
+ LayerAnimationSequence* sequence_2 = CreateLayerAnimationSequence();
+
+ observer_test_api_->AttachedToSequence(sequence_1);
+ observer_test_api_->AttachedToSequence(sequence_2);
+ observer_->OnLayerAnimationStarted(sequence_1);
+ observer_->OnLayerAnimationStarted(sequence_2);
+
+ observer_->SetActive();
+
+ EXPECT_TRUE(observer_->active());
+ EXPECT_TRUE(callbacks_->animations_started());
+ EXPECT_FALSE(callbacks_->animations_ended());
+}
+
+TEST_F(CallbackLayerAnimationObserverTest,
+ SetActiveWhenAllSequencesAreStartedAndOnlySomeWereCompleted) {
+ LayerAnimationSequence* sequence_1 = CreateLayerAnimationSequence();
+ LayerAnimationSequence* sequence_2 = CreateLayerAnimationSequence();
+
+ observer_test_api_->AttachedToSequence(sequence_1);
+ observer_test_api_->AttachedToSequence(sequence_2);
+ observer_->OnLayerAnimationStarted(sequence_1);
+ observer_->OnLayerAnimationStarted(sequence_2);
+ observer_->OnLayerAnimationEnded(sequence_1);
+
+ observer_->SetActive();
+
+ EXPECT_TRUE(observer_->active());
+ EXPECT_TRUE(callbacks_->animations_started());
+ EXPECT_FALSE(callbacks_->animations_ended());
+}
+
+TEST_F(CallbackLayerAnimationObserverTest,
+ SetActiveWhenAllSequencesWereCompleted) {
+ LayerAnimationSequence* sequence_1 = CreateLayerAnimationSequence();
+ LayerAnimationSequence* sequence_2 = CreateLayerAnimationSequence();
+
+ observer_test_api_->AttachedToSequence(sequence_1);
+ observer_test_api_->AttachedToSequence(sequence_2);
+ observer_->OnLayerAnimationStarted(sequence_1);
+ observer_->OnLayerAnimationStarted(sequence_2);
+ observer_->OnLayerAnimationEnded(sequence_1);
+ observer_->OnLayerAnimationEnded(sequence_2);
+
+ observer_->SetActive();
+
+ EXPECT_FALSE(observer_->active());
+ EXPECT_TRUE(callbacks_->animations_started());
+ EXPECT_TRUE(callbacks_->animations_ended());
+}
+
+TEST_F(CallbackLayerAnimationObserverTest,
+ SetActiveAgainAfterAllSequencesWereCompleted) {
+ LayerAnimationSequence* sequence_1 = CreateLayerAnimationSequence();
+ LayerAnimationSequence* sequence_2 = CreateLayerAnimationSequence();
+ LayerAnimationSequence* sequence_3 = CreateLayerAnimationSequence();
+ LayerAnimationSequence* sequence_4 = CreateLayerAnimationSequence();
+
+ observer_test_api_->AttachedToSequence(sequence_1);
+ observer_test_api_->AttachedToSequence(sequence_2);
+ observer_->OnLayerAnimationStarted(sequence_1);
+ observer_->OnLayerAnimationStarted(sequence_2);
+ observer_->OnLayerAnimationEnded(sequence_1);
+ observer_->OnLayerAnimationEnded(sequence_2);
+
+ observer_->SetActive();
+
+ EXPECT_FALSE(observer_->active());
+
+ observer_test_api_->AttachedToSequence(sequence_3);
+ observer_test_api_->AttachedToSequence(sequence_4);
+
+ callbacks_->ResetCallbackObservations();
+
+ observer_->SetActive();
+
+ EXPECT_TRUE(observer_->active());
+ EXPECT_FALSE(callbacks_->animations_started());
+ EXPECT_FALSE(callbacks_->animations_ended());
+ EXPECT_EQ(2, observer_->successful_count());
+
+ observer_->OnLayerAnimationStarted(sequence_3);
+ observer_->OnLayerAnimationStarted(sequence_4);
+
+ EXPECT_TRUE(observer_->active());
+ EXPECT_TRUE(callbacks_->animations_started());
+ EXPECT_FALSE(callbacks_->animations_ended());
+ EXPECT_EQ(2, observer_->successful_count());
+
+ observer_->OnLayerAnimationEnded(sequence_3);
+ observer_->OnLayerAnimationEnded(sequence_4);
+
+ EXPECT_FALSE(observer_->active());
+ EXPECT_TRUE(callbacks_->animations_started());
+ EXPECT_TRUE(callbacks_->animations_ended());
+ EXPECT_EQ(4, observer_->successful_count());
+}
+
+} // namespace test
+} // namespace ui
« no previous file with comments | « ui/compositor/callback_layer_animation_observer.cc ('k') | ui/compositor/compositor.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698