| // Copyright 2011 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/gfx/animation/animation_container.h" |
| |
| #include <memory> |
| |
| #include "base/run_loop.h" |
| #include "base/test/task_environment.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gfx/animation/animation_container_observer.h" |
| #include "ui/gfx/animation/animation_test_api.h" |
| #include "ui/gfx/animation/linear_animation.h" |
| #include "ui/gfx/animation/test_animation_delegate.h" |
| |
| namespace gfx { |
| |
| namespace { |
| |
| class FakeAnimationContainerObserver : public AnimationContainerObserver { |
| public: |
| FakeAnimationContainerObserver() |
| : progressed_count_(0), |
| empty_(false) { |
| } |
| |
| FakeAnimationContainerObserver(const FakeAnimationContainerObserver&) = |
| delete; |
| FakeAnimationContainerObserver& operator=( |
| const FakeAnimationContainerObserver&) = delete; |
| |
| int progressed_count() const { return progressed_count_; } |
| bool empty() const { return empty_; } |
| |
| private: |
| void AnimationContainerProgressed(AnimationContainer* container) override { |
| progressed_count_++; |
| } |
| |
| // Invoked when no more animations are being managed by this container. |
| void AnimationContainerEmpty(AnimationContainer* container) override { |
| empty_ = true; |
| } |
| |
| void AnimationContainerShuttingDown(AnimationContainer* container) override {} |
| |
| int progressed_count_; |
| bool empty_; |
| }; |
| |
| class TestAnimation : public LinearAnimation { |
| public: |
| explicit TestAnimation(AnimationDelegate* delegate) |
| : LinearAnimation(base::Milliseconds(20), 20, delegate) {} |
| |
| TestAnimation(const TestAnimation&) = delete; |
| TestAnimation& operator=(const TestAnimation&) = delete; |
| |
| void AnimateToState(double state) override {} |
| |
| using LinearAnimation::duration; |
| }; |
| |
| } // namespace |
| |
| class AnimationContainerTest: public testing::Test { |
| protected: |
| AnimationContainerTest() |
| : task_environment_( |
| base::test::SingleThreadTaskEnvironment::MainThreadType::UI) {} |
| |
| private: |
| base::test::SingleThreadTaskEnvironment task_environment_; |
| }; |
| |
| // Makes sure the animation ups the ref count of the container and releases it |
| // appropriately. |
| TEST_F(AnimationContainerTest, Ownership) { |
| TestAnimationDelegate delegate; |
| scoped_refptr<AnimationContainer> container(new AnimationContainer()); |
| std::unique_ptr<Animation> animation(new TestAnimation(&delegate)); |
| animation->SetContainer(container.get()); |
| // Setting the container should up the ref count. |
| EXPECT_FALSE(container->HasOneRef()); |
| |
| animation.reset(); |
| |
| // Releasing the animation should decrement the ref count. |
| EXPECT_TRUE(container->HasOneRef()); |
| } |
| |
| // Makes sure multiple animations are managed correctly. |
| TEST_F(AnimationContainerTest, Multi) { |
| TestAnimationDelegate delegate1; |
| TestAnimationDelegate delegate2; |
| |
| scoped_refptr<AnimationContainer> container(new AnimationContainer()); |
| TestAnimation animation1(&delegate1); |
| TestAnimation animation2(&delegate2); |
| animation1.SetContainer(container.get()); |
| animation2.SetContainer(container.get()); |
| |
| // Start both animations. |
| animation1.Start(); |
| EXPECT_TRUE(container->is_running()); |
| animation2.Start(); |
| EXPECT_TRUE(container->is_running()); |
| |
| // Run the message loop the delegate quits the message loop when notified. |
| base::RunLoop().Run(); |
| |
| // Both timers should have finished. |
| EXPECT_TRUE(delegate1.finished()); |
| EXPECT_TRUE(delegate2.finished()); |
| |
| // And the container should no longer be runnings. |
| EXPECT_FALSE(container->is_running()); |
| } |
| |
| // Makes sure observer is notified appropriately. |
| TEST_F(AnimationContainerTest, Observer) { |
| FakeAnimationContainerObserver observer; |
| TestAnimationDelegate delegate1; |
| |
| scoped_refptr<AnimationContainer> container(new AnimationContainer()); |
| container->set_observer(&observer); |
| TestAnimation animation1(&delegate1); |
| animation1.SetContainer(container.get()); |
| |
| // Start the animation. |
| animation1.Start(); |
| EXPECT_TRUE(container->is_running()); |
| |
| // Run the message loop. The delegate quits the message loop when notified. |
| base::RunLoop().Run(); |
| |
| EXPECT_EQ(1, observer.progressed_count()); |
| |
| // The timer should have finished. |
| EXPECT_TRUE(delegate1.finished()); |
| |
| EXPECT_TRUE(observer.empty()); |
| |
| // And the container should no longer be running. |
| EXPECT_FALSE(container->is_running()); |
| |
| container->set_observer(NULL); |
| } |
| |
| // Tests that calling SetAnimationRunner() keeps running animations at their |
| // current point. |
| TEST_F(AnimationContainerTest, AnimationsRunAcrossRunnerChange) { |
| TestAnimationDelegate delegate; |
| auto container = base::MakeRefCounted<AnimationContainer>(); |
| AnimationContainerTestApi test_api(container.get()); |
| TestAnimation animation(&delegate); |
| animation.SetContainer(container.get()); |
| |
| animation.Start(); |
| test_api.IncrementTime(animation.duration() / 2); |
| EXPECT_FALSE(delegate.finished()); |
| |
| container->SetAnimationRunner(nullptr); |
| AnimationRunner* runner = container->animation_runner_for_testing(); |
| ASSERT_TRUE(runner); |
| ASSERT_FALSE(runner->step_is_null_for_testing()); |
| EXPECT_FALSE(delegate.finished()); |
| |
| test_api.IncrementTime(animation.duration() / 2); |
| EXPECT_TRUE(delegate.finished()); |
| } |
| |
| } // namespace gfx |