910e62b5创建于 1月15日历史提交
// Copyright 2015 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/compositor/callback_layer_animation_observer.h"

#include <memory>

#include "base/functional/bind.h"
#include "base/memory/raw_ptr.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();

  TestCallbacks(const TestCallbacks&) = delete;
  TestCallbacks& operator=(const TestCallbacks&) = delete;

  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;
};

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();

  TestCallbacksThatExplicitlyDeletesObserver(
      const TestCallbacksThatExplicitlyDeletesObserver&) = delete;
  TestCallbacksThatExplicitlyDeletesObserver& operator=(
      const TestCallbacksThatExplicitlyDeletesObserver&) = delete;

  void set_observer_to_delete_in_animation_ended(
      std::unique_ptr<CallbackLayerAnimationObserver> observer) {
    observer_to_delete_in_animation_ended_ = std::move(observer);
  }

  void set_observer_to_delete_in_animation_started(
      std::unique_ptr<CallbackLayerAnimationObserver> observer) {
    observer_to_delete_in_animation_started_ = std::move(observer);
  }

  CallbackLayerAnimationObserver* observer_to_delete_in_animation_started() {
    return observer_to_delete_in_animation_started_.get();
  }

  CallbackLayerAnimationObserver* observer_to_delete_in_animation_ended() {
    return observer_to_delete_in_animation_ended_.get();
  }

  // TestCallbacks:
  void AnimationsStarted(
      const CallbackLayerAnimationObserver& observer) override;
  bool AnimationsEnded(const CallbackLayerAnimationObserver& observer) override;

 private:
  // The observer to delete, if non-NULL, in AnimationsStarted().
  std::unique_ptr<CallbackLayerAnimationObserver>
      observer_to_delete_in_animation_started_;

  // The observer to delete, if non-NULL, in AnimationsEnded().
  std::unique_ptr<CallbackLayerAnimationObserver>
      observer_to_delete_in_animation_ended_;
};

TestCallbacksThatExplicitlyDeletesObserver::
    TestCallbacksThatExplicitlyDeletesObserver() {}

void TestCallbacksThatExplicitlyDeletesObserver::AnimationsStarted(
    const CallbackLayerAnimationObserver& observer) {
  observer_to_delete_in_animation_started_.reset();
  TestCallbacks::AnimationsStarted(observer);
}

bool TestCallbacksThatExplicitlyDeletesObserver::AnimationsEnded(
    const CallbackLayerAnimationObserver& observer) {
  observer_to_delete_in_animation_ended_.reset();
  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(
      AnimationStartedCallback animation_started_callback,
      bool should_delete_observer,
      bool* destroyed);

  TestCallbackLayerAnimationObserver(
      AnimationEndedCallback animation_ended_callback,
      bool* destroyed);

  TestCallbackLayerAnimationObserver(
      const TestCallbackLayerAnimationObserver&) = delete;
  TestCallbackLayerAnimationObserver& operator=(
      const TestCallbackLayerAnimationObserver&) = delete;

  ~TestCallbackLayerAnimationObserver() override;

 private:
  raw_ptr<bool> destroyed_;
};

TestCallbackLayerAnimationObserver::TestCallbackLayerAnimationObserver(
    AnimationStartedCallback animation_started_callback,
    AnimationEndedCallback animation_ended_callback,
    bool* destroyed)
    : CallbackLayerAnimationObserver(animation_started_callback,
                                     animation_ended_callback),
      destroyed_(destroyed) {
  if (destroyed_)
    (*destroyed_) = false;
}

TestCallbackLayerAnimationObserver::TestCallbackLayerAnimationObserver(
    AnimationStartedCallback animation_started_callback,
    bool should_delete_observer,
    bool* destroyed)
    : CallbackLayerAnimationObserver(animation_started_callback,
                                     should_delete_observer),
      destroyed_(destroyed) {
  if (destroyed_)
    (*destroyed_) = false;
}

TestCallbackLayerAnimationObserver::TestCallbackLayerAnimationObserver(
    AnimationEndedCallback animation_ended_callback,
    bool* destroyed)
    : CallbackLayerAnimationObserver(animation_ended_callback),
      destroyed_(destroyed) {
  if (destroyed_)
    (*destroyed_) = false;
}

TestCallbackLayerAnimationObserver::~TestCallbackLayerAnimationObserver() {
  if (destroyed_)
    (*destroyed_) = true;
}

class CallbackLayerAnimationObserverTest : public testing::Test {
 public:
  CallbackLayerAnimationObserverTest();

  CallbackLayerAnimationObserverTest(
      const CallbackLayerAnimationObserverTest&) = delete;
  CallbackLayerAnimationObserverTest& operator=(
      const CallbackLayerAnimationObserverTest&) = delete;

  ~CallbackLayerAnimationObserverTest() override;

 protected:
  // Creates a LayerAnimationSequence.  The lifetime of the sequence will be
  // managed by this.
  LayerAnimationSequence* CreateLayerAnimationSequence();

  std::unique_ptr<TestCallbacks> callbacks_;

  std::unique_ptr<CallbackLayerAnimationObserver> observer_;

  std::unique_ptr<LayerAnimationObserverTestApi> observer_test_api_;

  // List of managaged sequences created by CreateLayerAnimationSequence() that
  // need to be destroyed.
  std::vector<std::unique_ptr<LayerAnimationSequence>> sequences_;
};

CallbackLayerAnimationObserverTest::CallbackLayerAnimationObserverTest()
    : callbacks_(new TestCallbacks()),
      observer_(new CallbackLayerAnimationObserver(
          base::BindRepeating(&TestCallbacks::AnimationsStarted,
                              base::Unretained(callbacks_.get())),
          base::BindRepeating(&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() {
  sequences_.emplace_back(new LayerAnimationSequence);
  return sequences_.back().get();
}

class CallbackLayerAnimationObserverTestOverwrite
    : public CallbackLayerAnimationObserverTest {
 public:
  CallbackLayerAnimationObserverTestOverwrite();

  CallbackLayerAnimationObserverTestOverwrite(
      const CallbackLayerAnimationObserverTestOverwrite&) = delete;
  CallbackLayerAnimationObserverTestOverwrite& operator=(
      const CallbackLayerAnimationObserverTestOverwrite&) = delete;

 protected:
  void AnimationStarted(const CallbackLayerAnimationObserver& observer);

  std::unique_ptr<CallbackLayerAnimationObserver> CreateAnimationObserver();
};

CallbackLayerAnimationObserverTestOverwrite::
    CallbackLayerAnimationObserverTestOverwrite() {
  observer_ = CreateAnimationObserver();
  observer_test_api_ =
      std::make_unique<LayerAnimationObserverTestApi>(observer_.get());
}

void CallbackLayerAnimationObserverTestOverwrite::AnimationStarted(
    const CallbackLayerAnimationObserver& observer) {
  observer_->OnLayerAnimationAborted(sequences_.front().get());
  observer_test_api_.reset();
  // Replace the current observer with a new observer so that the destructor
  // gets called on the current observer.
  observer_ = CreateAnimationObserver();
}

std::unique_ptr<CallbackLayerAnimationObserver>
CallbackLayerAnimationObserverTestOverwrite::CreateAnimationObserver() {
  return std::make_unique<CallbackLayerAnimationObserver>(
      base::BindRepeating(
          &CallbackLayerAnimationObserverTestOverwrite::AnimationStarted,
          base::Unretained(this)),
      base::BindRepeating([](const CallbackLayerAnimationObserver& observer) {
        return false;
      }));
}

TEST(CallbackLayerAnimationObserverDestructionTest, VerifyFalseAutoDelete) {
  TestCallbacks callbacks;
  callbacks.set_should_delete_observer_on_animations_ended(false);

  bool is_destroyed = false;

  TestCallbackLayerAnimationObserver* observer =
      new TestCallbackLayerAnimationObserver(
          base::BindRepeating(&TestCallbacks::AnimationsStarted,
                              base::Unretained(&callbacks)),
          false, &is_destroyed);
  observer->SetActive();

  EXPECT_FALSE(is_destroyed);
  delete observer;
}

TEST(CallbackLayerAnimationObserverDestructionTest, VerifyTrueAutoDelete) {
  TestCallbacks callbacks;
  callbacks.set_should_delete_observer_on_animations_ended(false);

  bool is_destroyed = false;

  TestCallbackLayerAnimationObserver* observer =
      new TestCallbackLayerAnimationObserver(
          base::BindRepeating(&TestCallbacks::AnimationsStarted,
                              base::Unretained(&callbacks)),
          true, &is_destroyed);
  observer->SetActive();

  EXPECT_TRUE(is_destroyed);
}

TEST(CallbackLayerAnimationObserverDestructionTest,
     AnimationEndedReturnsFalse) {
  TestCallbacks callbacks;
  callbacks.set_should_delete_observer_on_animations_ended(false);

  bool is_destroyed = false;

  TestCallbackLayerAnimationObserver* observer =
      new TestCallbackLayerAnimationObserver(
          base::BindRepeating(&TestCallbacks::AnimationsStarted,
                              base::Unretained(&callbacks)),
          base::BindRepeating(&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::BindRepeating(&TestCallbacks::AnimationsStarted,
                              base::Unretained(&callbacks)),
          base::BindRepeating(&TestCallbacks::AnimationsEnded,
                              base::Unretained(&callbacks)),
          &is_destroyed);
  observer->SetActive();

  EXPECT_TRUE(is_destroyed);
}

// Verifies that there are not heap-use-after-free errors when an observer has
// its animation aborted and it gets destroyed due to a
// unique_ptr<CallbackLayerAnimationObserver> being assigned a new value.
TEST_F(CallbackLayerAnimationObserverTestOverwrite,
       VerifyOverwriteOnAnimationStart) {
  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_FALSE(observer_->active());
}

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());
}

// 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;

  std::unique_ptr<TestCallbackLayerAnimationObserver> observer =
      std::make_unique<TestCallbackLayerAnimationObserver>(
          base::BindRepeating(&TestCallbacks::AnimationsStarted,
                              base::Unretained(&callbacks)),
          base::BindRepeating(&TestCallbacks::AnimationsEnded,
                              base::Unretained(&callbacks)),
          &is_destroyed);

  callbacks.set_observer_to_delete_in_animation_started(std::move(observer));

  callbacks.observer_to_delete_in_animation_started()->SetActive();

  EXPECT_TRUE(is_destroyed);
}

// Verifies that the CallbackLayerAnimationObserver is robust to explicit
// deletes caused as a side effect of calling the AnimationsStartedCallback()
// when all attached animation sequences detach. This test also guards against
// heap-use-after-free errors.
TEST_F(CallbackLayerAnimationObserverTest,
       ExplicitlyDeleteObserverInAnimationStartedCallbackSequencesDetached) {
  TestCallbacksThatExplicitlyDeletesObserver callbacks;
  callbacks.set_should_delete_observer_on_animations_ended(true);

  bool is_destroyed = false;

  std::unique_ptr<TestCallbackLayerAnimationObserver> observer =
      std::make_unique<TestCallbackLayerAnimationObserver>(
          base::BindRepeating(&TestCallbacks::AnimationsStarted,
                              base::Unretained(&callbacks)),
          base::BindRepeating(&TestCallbacks::AnimationsEnded,
                              base::Unretained(&callbacks)),
          &is_destroyed);

  callbacks.set_observer_to_delete_in_animation_started(std::move(observer));
  CallbackLayerAnimationObserver* observer_ptr =
      callbacks.observer_to_delete_in_animation_started();
  LayerAnimationObserverTestApi test_api(observer_ptr);

  LayerAnimationSequence* sequence_1 = CreateLayerAnimationSequence();

  test_api.AttachedToSequence(sequence_1);
  observer_ptr->SetActive();
  test_api.DetachedFromSequence(sequence_1, true);

  EXPECT_TRUE(is_destroyed);
  EXPECT_TRUE(callbacks.animations_started());

  // The observer was destroyed before the end notification could be dispatched.
  EXPECT_FALSE(callbacks.animations_ended());
}

// 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;

  std::unique_ptr<TestCallbackLayerAnimationObserver> observer =
      std::make_unique<TestCallbackLayerAnimationObserver>(
          base::BindRepeating(&TestCallbacks::AnimationsStarted,
                              base::Unretained(&callbacks)),
          base::BindRepeating(&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(std::move(observer));

  callbacks.observer_to_delete_in_animation_started()->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;

  std::unique_ptr<TestCallbackLayerAnimationObserver> observer =
      std::make_unique<TestCallbackLayerAnimationObserver>(
          base::BindRepeating(&TestCallbacks::AnimationsStarted,
                              base::Unretained(&callbacks)),
          base::BindRepeating(&TestCallbacks::AnimationsEnded,
                              base::Unretained(&callbacks)),
          &is_destroyed);

  callbacks.set_observer_to_delete_in_animation_ended(std::move(observer));

  callbacks.observer_to_delete_in_animation_ended()->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());
}

TEST_F(CallbackLayerAnimationObserverTest, DetachBeforeActive) {
  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_test_api_->DetachedFromSequence(sequence_1, true);
  observer_test_api_->DetachedFromSequence(sequence_2, true);

  observer_->SetActive();

  EXPECT_FALSE(observer_->active());
  EXPECT_TRUE(callbacks_->animations_started());
  EXPECT_TRUE(callbacks_->animations_ended());
}

TEST_F(CallbackLayerAnimationObserverTest, DetachAfterActive) {
  LayerAnimationSequence* sequence_1 = CreateLayerAnimationSequence();
  LayerAnimationSequence* sequence_2 = CreateLayerAnimationSequence();

  observer_test_api_->AttachedToSequence(sequence_1);
  observer_test_api_->AttachedToSequence(sequence_2);

  observer_->SetActive();

  observer_->OnLayerAnimationStarted(sequence_1);
  observer_->OnLayerAnimationEnded(sequence_1);
  observer_test_api_->DetachedFromSequence(sequence_1, true);
  observer_test_api_->DetachedFromSequence(sequence_2, true);

  EXPECT_FALSE(observer_->active());
  EXPECT_TRUE(callbacks_->animations_started());
  EXPECT_TRUE(callbacks_->animations_ended());
}

}  // namespace test
}  // namespace ui