| Index: cc/scheduler/begin_frame_source_unittest.cc | 
| diff --git a/cc/scheduler/begin_frame_source_unittest.cc b/cc/scheduler/begin_frame_source_unittest.cc | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..ec56bd30ce4362241c12d89fdab56aa412570152 | 
| --- /dev/null | 
| +++ b/cc/scheduler/begin_frame_source_unittest.cc | 
| @@ -0,0 +1,737 @@ | 
| +// Copyright 2011 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 <deque> | 
| +#include <string> | 
| + | 
| +#include "base/basictypes.h" | 
| +#include "base/gtest_prod_util.h" | 
| +#include "base/test/test_simple_task_runner.h" | 
| +#include "cc/scheduler/begin_frame_source.h" | 
| +#include "cc/test/begin_frame_args_test.h" | 
| +#include "cc/test/scheduler_test_common.h" | 
| +#include "testing/gmock/include/gmock/gmock.h" | 
| +#include "testing/gtest/include/gtest/gtest.h" | 
| + | 
| +// Macros to help set up expected calls on the MockBeginFrameObserver. | 
| +#define EXPECT_BEGIN_FRAME_DROP(obs, ...)                                      \ | 
| +  {                                                                            \ | 
| +    ::testing::Expectation exp =                                               \ | 
| +        EXPECT_CALL((obs),                                                     \ | 
| +                    OnBeginFrame(CreateBeginFrameArgsForTesting(__VA_ARGS__))) \ | 
| +            .InSequence((obs).sequence);                                       \ | 
| +  } | 
| + | 
| +#define EXPECT_BEGIN_FRAME_USED(obs, ...)                                      \ | 
| +  {                                                                            \ | 
| +    ::testing::Expectation exp =                                               \ | 
| +        EXPECT_CALL((obs),                                                     \ | 
| +                    OnBeginFrame(CreateBeginFrameArgsForTesting(__VA_ARGS__))) \ | 
| +            .InSequence((obs).sequence);                                       \ | 
| +    EXPECT_CALL((obs), LastUsedBeginFrameArgs())                               \ | 
| +        .Times(::testing::AnyNumber())                                         \ | 
| +        .After(exp)                                                            \ | 
| +        .WillRepeatedly(                                                       \ | 
| +            ::testing::Return(CreateBeginFrameArgsForTesting(__VA_ARGS__)));   \ | 
| +  } | 
| + | 
| +// Macros to send BeginFrameArgs on a FakeBeginFrameSink (and verify resulting | 
| +// observer behaviour). | 
| +#define SEND_BEGIN_FRAME(args_equal_to, source, ...)                       \ | 
| +  {                                                                        \ | 
| +    BeginFrameArgs old_args = (source).TestLastUsedBeginFrameArgs();       \ | 
| +    BeginFrameArgs new_args = CreateBeginFrameArgsForTesting(__VA_ARGS__); \ | 
| +    ASSERT_TRUE(!(old_args == new_args));                                  \ | 
| +    (source).TestOnBeginFrame(new_args);                                   \ | 
| +    EXPECT_EQ(args_equal_to, (source).TestLastUsedBeginFrameArgs());       \ | 
| +  } | 
| + | 
| +#define SEND_BEGIN_FRAME_DROP(...) \ | 
| +  SEND_BEGIN_FRAME(old_args,       \ | 
| +                   __VA_ARGS__);  // When dropping LastUsedBeginFrameArgs | 
| +                                  // **shouldn't** change. | 
| + | 
| +#define SEND_BEGIN_FRAME_USED(...) \ | 
| +  SEND_BEGIN_FRAME(new_args, __VA_ARGS__);  // When used LastUsedBeginFrameArgs | 
| +                                            // **should** be updated. | 
| + | 
| +namespace cc { | 
| +namespace { | 
| + | 
| +class MockBeginFrameObserver : public BeginFrameObserver { | 
| + public: | 
| +  MOCK_METHOD1(OnBeginFrame, void(const BeginFrameArgs&)); | 
| +  MOCK_CONST_METHOD0(LastUsedBeginFrameArgs, const BeginFrameArgs()); | 
| + | 
| +  virtual void AsValueInto(base::debug::TracedValue* dict) const { | 
| +    dict->SetString("type", "MockBeginFrameObserver"); | 
| +    dict->BeginDictionary("last_begin_frame_args"); | 
| +    LastUsedBeginFrameArgs().AsValueInto(dict); | 
| +    dict->EndDictionary(); | 
| +  } | 
| + | 
| +  // A value different from the normal default returned by a BeginFrameObserver | 
| +  // so it is easiable traced back here. | 
| +  static const BeginFrameArgs kDefaultBeginFrameArgs; | 
| + | 
| +  MockBeginFrameObserver() { | 
| +    // Set a "default" value returned by LastUsedBeginFrameArgs so that gMock | 
| +    // doesn't fail an assert and instead returns useful information. | 
| +    EXPECT_CALL(*this, LastUsedBeginFrameArgs()) | 
| +        .Times(::testing::AnyNumber()) | 
| +        .InSequence(sequence) | 
| +        .WillRepeatedly(::testing::Return(kDefaultBeginFrameArgs)); | 
| +  } | 
| +  virtual ~MockBeginFrameObserver() {} | 
| + | 
| +  ::testing::Sequence sequence; | 
| +}; | 
| + | 
| +TEST(MockBeginFrameObserverTest, ExpectOnBeginFrame) { | 
| +  ::testing::NiceMock<MockBeginFrameObserver> obs; | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300); | 
| + | 
| +  EXPECT_EQ(obs.LastUsedBeginFrameArgs(), | 
| +            MockBeginFrameObserver::kDefaultBeginFrameArgs); | 
| + | 
| +  obs.OnBeginFrame(CreateBeginFrameArgsForTesting( | 
| +      100, 200, 300));  // One call to LastUsedBeginFrameArgs | 
| +  EXPECT_EQ(obs.LastUsedBeginFrameArgs(), | 
| +            CreateBeginFrameArgsForTesting(100, 200, 300)); | 
| + | 
| +  obs.OnBeginFrame(CreateBeginFrameArgsForTesting( | 
| +      400, 600, 300));  // Multiple calls to LastUsedBeginFrameArgs | 
| +  EXPECT_EQ(obs.LastUsedBeginFrameArgs(), | 
| +            CreateBeginFrameArgsForTesting(400, 600, 300)); | 
| +  EXPECT_EQ(obs.LastUsedBeginFrameArgs(), | 
| +            CreateBeginFrameArgsForTesting(400, 600, 300)); | 
| + | 
| +  obs.OnBeginFrame(CreateBeginFrameArgsForTesting( | 
| +      700, 900, 300));  // No calls to LastUsedBeginFrameArgs | 
| +} | 
| + | 
| +TEST(MockBeginFrameObserverTest, ExpectOnBeginFrameStatus) { | 
| +  ::testing::NiceMock<MockBeginFrameObserver> obs; | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300); | 
| +  EXPECT_BEGIN_FRAME_DROP(obs, 400, 600, 300); | 
| +  EXPECT_BEGIN_FRAME_DROP(obs, 450, 650, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300); | 
| + | 
| +  EXPECT_EQ(obs.LastUsedBeginFrameArgs(), | 
| +            MockBeginFrameObserver::kDefaultBeginFrameArgs); | 
| + | 
| +  // Used | 
| +  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(100, 200, 300)); | 
| +  EXPECT_EQ(obs.LastUsedBeginFrameArgs(), | 
| +            CreateBeginFrameArgsForTesting(100, 200, 300)); | 
| + | 
| +  // Dropped | 
| +  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(400, 600, 300)); | 
| +  EXPECT_EQ(obs.LastUsedBeginFrameArgs(), | 
| +            CreateBeginFrameArgsForTesting(100, 200, 300)); | 
| + | 
| +  // Dropped | 
| +  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(450, 650, 300)); | 
| +  EXPECT_EQ(obs.LastUsedBeginFrameArgs(), | 
| +            CreateBeginFrameArgsForTesting(100, 200, 300)); | 
| + | 
| +  // Used | 
| +  obs.OnBeginFrame(CreateBeginFrameArgsForTesting(700, 900, 300)); | 
| +  EXPECT_EQ(obs.LastUsedBeginFrameArgs(), | 
| +            CreateBeginFrameArgsForTesting(700, 900, 300)); | 
| +} | 
| + | 
| +const BeginFrameArgs MockBeginFrameObserver::kDefaultBeginFrameArgs = | 
| +    CreateBeginFrameArgsForTesting(-1, -1, -1); | 
| + | 
| +// BeginFrameObserverMixIn testing --------------------------------------- | 
| +class MockMinimalBeginFrameObserverMixIn : public BeginFrameObserverMixIn { | 
| + public: | 
| +  MOCK_METHOD1(OnBeginFrameMixInDelegate, bool(const BeginFrameArgs&)); | 
| +  int64_t dropped_begin_frame_args() const { return dropped_begin_frame_args_; } | 
| +}; | 
| + | 
| +TEST(BeginFrameObserverMixInTest, OnBeginFrameImplementation) { | 
| +  using ::testing::Return; | 
| +  MockMinimalBeginFrameObserverMixIn obs; | 
| +  ::testing::InSequence ordered;  // These calls should be ordered | 
| + | 
| +  // Initial conditions | 
| +  EXPECT_EQ(BeginFrameArgs(), obs.LastUsedBeginFrameArgs()); | 
| +  EXPECT_EQ(0, obs.dropped_begin_frame_args()); | 
| + | 
| +#ifndef NDEBUG | 
| +  EXPECT_DEATH({ obs.OnBeginFrame(BeginFrameArgs()); }, ""); | 
| +#endif | 
| + | 
| +  BeginFrameArgs args1 = CreateBeginFrameArgsForTesting(100, 200, 300); | 
| +  EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args1)).WillOnce(Return(true)); | 
| +  obs.OnBeginFrame(args1); | 
| +  EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs()); | 
| +  EXPECT_EQ(0, obs.dropped_begin_frame_args()); | 
| + | 
| +#ifndef NDEBUG | 
| +  EXPECT_DEATH( | 
| +      { obs.OnBeginFrame(CreateBeginFrameArgsForTesting(50, 200, 300)); }, ""); | 
| +#endif | 
| + | 
| +  // Returning false shouldn't update the LastUsedBeginFrameArgs value. | 
| +  BeginFrameArgs args2 = CreateBeginFrameArgsForTesting(200, 300, 400); | 
| +  EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args2)).WillOnce(Return(false)); | 
| +  obs.OnBeginFrame(args2); | 
| +  EXPECT_EQ(args1, obs.LastUsedBeginFrameArgs()); | 
| +  EXPECT_EQ(1, obs.dropped_begin_frame_args()); | 
| + | 
| +  BeginFrameArgs args3 = CreateBeginFrameArgsForTesting(150, 300, 400); | 
| +  EXPECT_CALL(obs, OnBeginFrameMixInDelegate(args3)).WillOnce(Return(true)); | 
| +  obs.OnBeginFrame(args3); | 
| +  EXPECT_EQ(args3, obs.LastUsedBeginFrameArgs()); | 
| +  EXPECT_EQ(1, obs.dropped_begin_frame_args()); | 
| +} | 
| + | 
| +// BeginFrameSource testing ---------------------------------------------- | 
| +class BeginFrameSourceTest : public ::testing::Test {}; | 
| + | 
| +TEST_F(BeginFrameSourceTest, ObserverManipulation) { | 
| +  MockBeginFrameObserver obs; | 
| +  MockBeginFrameObserver otherObs; | 
| +  FakeBeginFrameSource source; | 
| + | 
| +  source.AddObserver(&obs); | 
| +  EXPECT_EQ(&obs, source.GetObserver()); | 
| + | 
| +#ifndef NDEBUG | 
| +  // Adding an observer when an observer already exists should DCHECK fail. | 
| +  EXPECT_DEATH({ source.AddObserver(&otherObs); }, ""); | 
| + | 
| +  // Removing wrong observer should DCHECK fail. | 
| +  EXPECT_DEATH({ source.RemoveObserver(&otherObs); }, ""); | 
| + | 
| +  // Removing an observer when there is no observer should DCHECK fail. | 
| +  EXPECT_DEATH({ | 
| +                 source.RemoveObserver(&obs); | 
| +                 source.RemoveObserver(&obs); | 
| +               }, | 
| +               ""); | 
| +#endif | 
| +  source.RemoveObserver(&obs); | 
| + | 
| +  source.AddObserver(&otherObs); | 
| +  EXPECT_EQ(&otherObs, source.GetObserver()); | 
| +  source.RemoveObserver(&otherObs); | 
| +} | 
| + | 
| +TEST_F(BeginFrameSourceTest, Observer) { | 
| +  FakeBeginFrameSource source; | 
| +  MockBeginFrameObserver obs; | 
| +  source.AddObserver(&obs); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300); | 
| +  EXPECT_BEGIN_FRAME_DROP(obs, 400, 600, 300); | 
| +  EXPECT_BEGIN_FRAME_DROP(obs, 450, 650, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300); | 
| + | 
| +  SEND_BEGIN_FRAME_USED(source, 100, 200, 300); | 
| +  SEND_BEGIN_FRAME_DROP(source, 400, 600, 300); | 
| +  SEND_BEGIN_FRAME_DROP(source, 450, 650, 300); | 
| +  SEND_BEGIN_FRAME_USED(source, 700, 900, 300); | 
| +} | 
| + | 
| +TEST_F(BeginFrameSourceTest, NoObserver) { | 
| +  FakeBeginFrameSource source; | 
| +  SEND_BEGIN_FRAME_DROP(source, 100, 200, 300); | 
| +} | 
| + | 
| +class LoopingBeginFrameObserver : public BeginFrameObserverMixIn { | 
| + public: | 
| +  BeginFrameSource* source_; | 
| + | 
| +  virtual void AsValueInto(base::debug::TracedValue* dict) const OVERRIDE { | 
| +    dict->SetString("type", "LoopingBeginFrameObserver"); | 
| +    dict->BeginDictionary("source"); | 
| +    source_->AsValueInto(dict); | 
| +    dict->EndDictionary(); | 
| +  } | 
| + | 
| + protected: | 
| +  // BeginFrameObserverMixIn | 
| +  virtual bool OnBeginFrameMixInDelegate(const BeginFrameArgs& args) OVERRIDE { | 
| +    return true; | 
| +  } | 
| +}; | 
| + | 
| +TEST_F(BeginFrameSourceTest, DetectAsValueIntoLoop) { | 
| +  LoopingBeginFrameObserver obs; | 
| +  FakeBeginFrameSource source; | 
| + | 
| +  obs.source_ = &source; | 
| +  source.AddObserver(&obs); | 
| + | 
| +  scoped_refptr<base::debug::TracedValue> state = | 
| +      new base::debug::TracedValue(); | 
| +  source.AsValueInto(state.get()); | 
| +} | 
| + | 
| +// BackToBackBeginFrameSource testing ----------------------------------------- | 
| +class TestBackToBackBeginFrameSource : public BackToBackBeginFrameSource { | 
| + public: | 
| +  static scoped_ptr<TestBackToBackBeginFrameSource> Create( | 
| +      scoped_refptr<TestNowSource> now_src, | 
| +      base::SingleThreadTaskRunner* task_runner) { | 
| +    return make_scoped_ptr( | 
| +        new TestBackToBackBeginFrameSource(now_src, task_runner)); | 
| +  } | 
| + | 
| + protected: | 
| +  TestBackToBackBeginFrameSource(scoped_refptr<TestNowSource> now_src, | 
| +                                 base::SingleThreadTaskRunner* task_runner) | 
| +      : BackToBackBeginFrameSource(task_runner), now_src_(now_src) {} | 
| + | 
| +  virtual base::TimeTicks Now() OVERRIDE { return now_src_->Now(); } | 
| + | 
| +  scoped_refptr<TestNowSource> now_src_; | 
| +}; | 
| + | 
| +class BackToBackBeginFrameSourceTest : public ::testing::Test { | 
| + public: | 
| +  static const int64_t kDeadline; | 
| +  static const int64_t kInterval; | 
| + | 
| +  scoped_refptr<TestNowSource> now_src_; | 
| +  scoped_refptr<OrderedSimpleTaskRunner> task_runner_; | 
| +  scoped_ptr<TestBackToBackBeginFrameSource> source_; | 
| +  scoped_ptr<MockBeginFrameObserver> obs_; | 
| + | 
| +  virtual void SetUp() OVERRIDE { | 
| +    now_src_ = TestNowSource::Create(1000); | 
| +    task_runner_ = | 
| +        make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_, false)); | 
| +    task_runner_->SetRunTaskLimit(1); | 
| +    source_ = | 
| +        TestBackToBackBeginFrameSource::Create(now_src_, task_runner_.get()); | 
| +    obs_ = make_scoped_ptr(new ::testing::StrictMock<MockBeginFrameObserver>()); | 
| +    source_->AddObserver(obs_.get()); | 
| +  } | 
| + | 
| +  virtual void TearDown() OVERRIDE { obs_.reset(); } | 
| +}; | 
| + | 
| +const int64_t BackToBackBeginFrameSourceTest::kDeadline = | 
| +    BeginFrameArgs::DefaultInterval().ToInternalValue(); | 
| + | 
| +const int64_t BackToBackBeginFrameSourceTest::kInterval = | 
| +    BeginFrameArgs::DefaultInterval().ToInternalValue(); | 
| + | 
| +TEST_F(BackToBackBeginFrameSourceTest, SetNeedsBeginFramesSendsBeginFrame) { | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval); | 
| +  source_->SetNeedsBeginFrames(true); | 
| +  EXPECT_TRUE(task_runner_->HasPendingTasks()); | 
| +  task_runner_->RunUntilIdle(); | 
| + | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1100, 1100 + kDeadline, kInterval); | 
| +  now_src_->AdvanceNowMicroseconds(100); | 
| +  source_->DidFinishFrame(0); | 
| +  task_runner_->RunUntilIdle(); | 
| +} | 
| + | 
| +TEST_F(BackToBackBeginFrameSourceTest, | 
| +       DidFinishFrameThenSetNeedsBeginFramesProducesNoFrame) { | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval); | 
| +  source_->SetNeedsBeginFrames(true); | 
| +  task_runner_->RunUntilIdle(); | 
| + | 
| +  source_->SetNeedsBeginFrames(false); | 
| +  source_->DidFinishFrame(0); | 
| + | 
| +  EXPECT_FALSE(task_runner_->HasPendingTasks()); | 
| +} | 
| + | 
| +TEST_F(BackToBackBeginFrameSourceTest, | 
| +       SetNeedsBeginFramesThenDidFinishFrameProducesNoFrame) { | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval); | 
| +  source_->SetNeedsBeginFrames(true); | 
| +  task_runner_->RunUntilIdle(); | 
| + | 
| +  now_src_->AdvanceNowMicroseconds(100); | 
| +  source_->DidFinishFrame(0); | 
| +  source_->SetNeedsBeginFrames(false); | 
| + | 
| +  EXPECT_TRUE(task_runner_->HasPendingTasks()); | 
| +  task_runner_->RunUntilIdle(); | 
| +} | 
| + | 
| +TEST_F(BackToBackBeginFrameSourceTest, | 
| +       DidFinishFrameThenTogglingSetNeedsBeginFramesProducesCorrectFrame) { | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval); | 
| +  source_->SetNeedsBeginFrames(true); | 
| +  task_runner_->RunUntilIdle(); | 
| + | 
| +  now_src_->AdvanceNowMicroseconds(100); | 
| + | 
| +  source_->SetNeedsBeginFrames(false); | 
| +  now_src_->AdvanceNowMicroseconds(10); | 
| +  source_->DidFinishFrame(0); | 
| +  now_src_->AdvanceNowMicroseconds(10); | 
| +  source_->SetNeedsBeginFrames(false); | 
| +  now_src_->AdvanceNowMicroseconds(10); | 
| +  source_->SetNeedsBeginFrames(true); | 
| + | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1130, 1130 + kDeadline, kInterval); | 
| +  EXPECT_TRUE(task_runner_->HasPendingTasks()); | 
| +  task_runner_->RunUntilIdle(); | 
| +} | 
| + | 
| +TEST_F(BackToBackBeginFrameSourceTest, | 
| +       TogglingSetNeedsBeginFramesThenDidFinishFrameProducesCorrectFrame) { | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval); | 
| +  source_->SetNeedsBeginFrames(true); | 
| +  task_runner_->RunUntilIdle(); | 
| + | 
| +  now_src_->AdvanceNowMicroseconds(100); | 
| +  source_->DidFinishFrame(0); | 
| +  now_src_->AdvanceNowMicroseconds(10); | 
| +  source_->SetNeedsBeginFrames(false); | 
| +  now_src_->AdvanceNowMicroseconds(10); | 
| +  source_->SetNeedsBeginFrames(true); | 
| +  now_src_->AdvanceNowMicroseconds(10); | 
| + | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1130, 1130 + kDeadline, kInterval); | 
| +  EXPECT_TRUE(task_runner_->HasPendingTasks()); | 
| +  task_runner_->RunUntilIdle(); | 
| +} | 
| + | 
| +TEST_F(BackToBackBeginFrameSourceTest, DidFinishFrameNeedsBeginFrameFalse) { | 
| +  source_->SetNeedsBeginFrames(false); | 
| +  source_->DidFinishFrame(0); | 
| +  EXPECT_FALSE(task_runner_->RunPendingTasks()); | 
| +} | 
| + | 
| +TEST_F(BackToBackBeginFrameSourceTest, DidFinishFrameRemainingFrames) { | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval); | 
| +  source_->SetNeedsBeginFrames(true); | 
| +  task_runner_->RunUntilIdle(); | 
| + | 
| +  now_src_->AdvanceNowMicroseconds(100); | 
| + | 
| +  source_->DidFinishFrame(3); | 
| +  EXPECT_FALSE(task_runner_->HasPendingTasks()); | 
| +  source_->DidFinishFrame(2); | 
| +  EXPECT_FALSE(task_runner_->HasPendingTasks()); | 
| +  source_->DidFinishFrame(1); | 
| +  EXPECT_FALSE(task_runner_->HasPendingTasks()); | 
| + | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1100, 1100 + kDeadline, kInterval); | 
| +  source_->DidFinishFrame(0); | 
| +  EXPECT_EQ(base::TimeDelta(), task_runner_->DelayToNextTaskTime()); | 
| +  task_runner_->RunUntilIdle(); | 
| +} | 
| + | 
| +TEST_F(BackToBackBeginFrameSourceTest, DidFinishFrameMultipleCallsIdempotent) { | 
| +  source_->SetNeedsBeginFrames(true); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval); | 
| +  task_runner_->RunUntilIdle(); | 
| + | 
| +  now_src_->AdvanceNowMicroseconds(100); | 
| +  source_->DidFinishFrame(0); | 
| +  source_->DidFinishFrame(0); | 
| +  source_->DidFinishFrame(0); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1100, 1100 + kDeadline, kInterval); | 
| +  task_runner_->RunUntilIdle(); | 
| + | 
| +  now_src_->AdvanceNowMicroseconds(100); | 
| +  source_->DidFinishFrame(0); | 
| +  source_->DidFinishFrame(0); | 
| +  source_->DidFinishFrame(0); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1200, 1200 + kDeadline, kInterval); | 
| +  task_runner_->RunUntilIdle(); | 
| +} | 
| + | 
| +TEST_F(BackToBackBeginFrameSourceTest, DelayInPostedTaskProducesCorrectFrame) { | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1000, 1000 + kDeadline, kInterval); | 
| +  source_->SetNeedsBeginFrames(true); | 
| +  task_runner_->RunUntilIdle(); | 
| + | 
| +  now_src_->AdvanceNowMicroseconds(100); | 
| +  source_->DidFinishFrame(0); | 
| +  now_src_->AdvanceNowMicroseconds(50); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 1150, 1150 + kDeadline, kInterval); | 
| + | 
| +  EXPECT_TRUE(task_runner_->HasPendingTasks()); | 
| +  task_runner_->RunUntilIdle(); | 
| +} | 
| + | 
| +// SyntheticBeginFrameSource testing ------------------------------------------ | 
| +class SyntheticBeginFrameSourceTest : public ::testing::Test { | 
| + public: | 
| +  scoped_refptr<TestNowSource> now_src_; | 
| +  scoped_refptr<OrderedSimpleTaskRunner> task_runner_; | 
| +  scoped_ptr<TestSyntheticBeginFrameSource> source_; | 
| +  scoped_ptr<MockBeginFrameObserver> obs_; | 
| + | 
| +  virtual void SetUp() OVERRIDE { | 
| +    now_src_ = TestNowSource::Create(1000); | 
| +    task_runner_ = | 
| +        make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_, false)); | 
| +    source_ = TestSyntheticBeginFrameSource::Create( | 
| +        now_src_, task_runner_.get(), base::TimeDelta::FromMicroseconds(10000)); | 
| +    obs_ = make_scoped_ptr(new MockBeginFrameObserver()); | 
| +    source_->AddObserver(obs_.get()); | 
| +  } | 
| + | 
| +  virtual void TearDown() OVERRIDE { obs_.reset(); } | 
| +}; | 
| + | 
| +TEST_F(SyntheticBeginFrameSourceTest, | 
| +       SetNeedsBeginFramesCallsOnBeginFrameWithMissedTick) { | 
| +  now_src_->SetNowMicroseconds(10010); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 10000, 20000, 10000, BeginFrameArgs::MISSED); | 
| +  source_->SetNeedsBeginFrames(true);  // Should cause the last tick to be sent | 
| +  // No tasks should need to be run for this to occur. | 
| +} | 
| + | 
| +TEST_F(SyntheticBeginFrameSourceTest, | 
| +       SetNeedsBeginFramesCallsCausesOnBeginFrame) { | 
| +  source_->SetNeedsBeginFrames(true); | 
| +  EXPECT_EQ(10000, task_runner_->NextTaskTime().ToInternalValue()); | 
| + | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 10000, 20000, 10000); | 
| +  now_src_->SetNowMicroseconds(10010); | 
| +  task_runner_->RunPendingTasks(); | 
| +} | 
| + | 
| +TEST_F(SyntheticBeginFrameSourceTest, BasicOperation) { | 
| +  task_runner_->SetAutoAdvanceNowToPendingTasks(true); | 
| + | 
| +  source_->SetNeedsBeginFrames(true); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 10000, 20000, 10000); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 20000, 30000, 10000); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 30000, 40000, 10000); | 
| +  task_runner_->RunUntilTime(base::TimeTicks::FromInternalValue(30001)); | 
| + | 
| +  source_->SetNeedsBeginFrames(false); | 
| +  // No new frames.... | 
| +  task_runner_->RunUntilTime(base::TimeTicks::FromInternalValue(60000)); | 
| +} | 
| + | 
| +TEST_F(SyntheticBeginFrameSourceTest, VSyncChanges) { | 
| +  task_runner_->SetAutoAdvanceNowToPendingTasks(true); | 
| +  source_->SetNeedsBeginFrames(true); | 
| + | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 10000, 20000, 10000); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 20000, 30000, 10000); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 30000, 40000, 10000); | 
| +  task_runner_->RunUntilTime(base::TimeTicks::FromInternalValue(30001)); | 
| + | 
| +  // Update the vsync information | 
| +  source_->OnUpdateVSyncParameters(base::TimeTicks::FromInternalValue(27500), | 
| +                                   base::TimeDelta::FromMicroseconds(10001)); | 
| + | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 40000, 47502, 10001); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 47502, 57503, 10001); | 
| +  EXPECT_BEGIN_FRAME_USED(*obs_, 57503, 67504, 10001); | 
| +  task_runner_->RunUntilTime(base::TimeTicks::FromInternalValue(60000)); | 
| +} | 
| + | 
| +// BeginFrameSourceMultiplexer testing ----------------------------------- | 
| +class BeginFrameSourceMultiplexerTest : public ::testing::Test { | 
| + protected: | 
| +  virtual void SetUp() OVERRIDE { | 
| +    mux_ = BeginFrameSourceMultiplexer::Create(); | 
| + | 
| +    source1_store_ = make_scoped_ptr(new FakeBeginFrameSource()); | 
| +    source2_store_ = make_scoped_ptr(new FakeBeginFrameSource()); | 
| +    source3_store_ = make_scoped_ptr(new FakeBeginFrameSource()); | 
| + | 
| +    source1_ = source1_store_.get(); | 
| +    source2_ = source2_store_.get(); | 
| +    source3_ = source3_store_.get(); | 
| +  } | 
| + | 
| +  virtual void TearDown() OVERRIDE { | 
| +    // Make sure the mux is torn down before the sources. | 
| +    mux_.reset(); | 
| +  } | 
| + | 
| +  scoped_ptr<BeginFrameSourceMultiplexer> mux_; | 
| +  FakeBeginFrameSource* source1_; | 
| +  FakeBeginFrameSource* source2_; | 
| +  FakeBeginFrameSource* source3_; | 
| + | 
| + private: | 
| +  scoped_ptr<FakeBeginFrameSource> source1_store_; | 
| +  scoped_ptr<FakeBeginFrameSource> source2_store_; | 
| +  scoped_ptr<FakeBeginFrameSource> source3_store_; | 
| +}; | 
| + | 
| +TEST_F(BeginFrameSourceMultiplexerTest, SourcesManipulation) { | 
| +  EXPECT_EQ(NULL, mux_->ActiveSource()); | 
| + | 
| +  mux_->AddSource(source1_); | 
| +  EXPECT_EQ(source1_, mux_->ActiveSource()); | 
| + | 
| +  mux_->SetActiveSource(NULL); | 
| +  EXPECT_EQ(NULL, mux_->ActiveSource()); | 
| + | 
| +  mux_->SetActiveSource(source1_); | 
| + | 
| +#ifndef NDEBUG | 
| +  // Setting a source which isn't in the mux as active should DCHECK fail. | 
| +  EXPECT_DEATH({ mux_->SetActiveSource(source2_); }, ""); | 
| + | 
| +  // Adding a source which is already added should DCHECK fail. | 
| +  EXPECT_DEATH({ mux_->AddSource(source1_); }, ""); | 
| + | 
| +  // Removing a source which isn't in the mux should DCHECK fail. | 
| +  EXPECT_DEATH({ mux_->RemoveSource(source2_); }, ""); | 
| + | 
| +  // Removing the active source fails | 
| +  EXPECT_DEATH({ mux_->RemoveSource(source1_); }, ""); | 
| +#endif | 
| + | 
| +  // Test manipulation doesn't segfault. | 
| +  mux_->AddSource(source2_); | 
| +  mux_->RemoveSource(source2_); | 
| + | 
| +  mux_->AddSource(source2_); | 
| +  mux_->SetActiveSource(source2_); | 
| +  EXPECT_EQ(source2_, mux_->ActiveSource()); | 
| + | 
| +  mux_->RemoveSource(source1_); | 
| +} | 
| + | 
| +TEST_F(BeginFrameSourceMultiplexerTest, NeedsBeginFrames) { | 
| +  mux_->AddSource(source1_); | 
| +  mux_->AddSource(source2_); | 
| +  mux_->SetActiveSource(source1_); | 
| +  EXPECT_EQ(source1_->needs_begin_frames_, false); | 
| +  EXPECT_EQ(source2_->needs_begin_frames_, false); | 
| + | 
| +  // Check SetNeedsFrames works | 
| +  mux_->SetNeedsBeginFrames(true); | 
| +  EXPECT_EQ(source1_->needs_begin_frames_, true); | 
| +  EXPECT_EQ(source2_->needs_begin_frames_, false); | 
| + | 
| +  mux_->SetNeedsBeginFrames(false); | 
| +  EXPECT_EQ(source1_->needs_begin_frames_, false); | 
| +  EXPECT_EQ(source2_->needs_begin_frames_, false); | 
| + | 
| +  // Checking that switching the source makes SetNeedsFrames on the | 
| +  // subsources correctly. | 
| +  mux_->SetNeedsBeginFrames(true); | 
| + | 
| +  mux_->SetActiveSource(source1_); | 
| +  EXPECT_EQ(source1_->needs_begin_frames_, true); | 
| +  EXPECT_EQ(source2_->needs_begin_frames_, false); | 
| + | 
| +  mux_->SetActiveSource(source2_); | 
| +  EXPECT_EQ(source1_->needs_begin_frames_, false); | 
| +  EXPECT_EQ(source2_->needs_begin_frames_, true); | 
| +} | 
| + | 
| +TEST_F(BeginFrameSourceMultiplexerTest, BeginFramesSimple) { | 
| +  mux_->AddSource(source1_); | 
| +  mux_->AddSource(source2_); | 
| +  mux_->SetActiveSource(source1_); | 
| + | 
| +  MockBeginFrameObserver obs; | 
| +  mux_->AddObserver(&obs); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300); | 
| + | 
| +  mux_->SetActiveSource(source1_); | 
| + | 
| +  SEND_BEGIN_FRAME_USED(*source1_, 100, 200, 300); | 
| +  SEND_BEGIN_FRAME_DROP(*source2_, 200, 500, 300); | 
| + | 
| +  mux_->SetActiveSource(source2_); | 
| +  SEND_BEGIN_FRAME_USED(*source2_, 400, 600, 300); | 
| +  SEND_BEGIN_FRAME_DROP(*source1_, 500, 700, 300); | 
| +} | 
| + | 
| +TEST_F(BeginFrameSourceMultiplexerTest, BeginFramesBackwardsProtection) { | 
| +  mux_->AddSource(source1_); | 
| +  mux_->AddSource(source2_); | 
| + | 
| +  MockBeginFrameObserver obs; | 
| +  mux_->AddObserver(&obs); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 1000, 1200, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 1001, 1201, 301); | 
| + | 
| +  mux_->SetActiveSource(source1_); | 
| +  SEND_BEGIN_FRAME_USED(*source1_, 400, 600, 300); | 
| +  SEND_BEGIN_FRAME_USED(*source1_, 700, 900, 300); | 
| + | 
| +  mux_->SetActiveSource(source2_); | 
| +  SEND_BEGIN_FRAME_DROP(*source2_, 699, 899, 300); | 
| +  SEND_BEGIN_FRAME_USED(*source2_, 1000, 1200, 300); | 
| + | 
| +  mux_->SetActiveSource(source1_); | 
| +  SEND_BEGIN_FRAME_USED(*source1_, 1001, 1201, 301); | 
| +} | 
| + | 
| +TEST_F(BeginFrameSourceMultiplexerTest, MinimumIntervalNegativeFails) { | 
| +#ifndef NDEBUG | 
| +  EXPECT_DEATH( | 
| +      { mux_->SetMinimumInterval(base::TimeDelta::FromInternalValue(-100)); }, | 
| +      ""); | 
| +#endif | 
| +} | 
| + | 
| +TEST_F(BeginFrameSourceMultiplexerTest, MinimumIntervalZero) { | 
| +  mux_->SetMinimumInterval(base::TimeDelta()); | 
| +  mux_->AddSource(source1_); | 
| + | 
| +  MockBeginFrameObserver obs; | 
| +  mux_->AddObserver(&obs); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300); | 
| + | 
| +  SEND_BEGIN_FRAME_USED(*source1_, 100, 200, 300); | 
| +  SEND_BEGIN_FRAME_USED(*source1_, 400, 600, 300); | 
| +  SEND_BEGIN_FRAME_USED(*source1_, 700, 900, 300); | 
| +} | 
| + | 
| +TEST_F(BeginFrameSourceMultiplexerTest, MinimumIntervalBasic) { | 
| +  mux_->SetMinimumInterval(base::TimeDelta::FromInternalValue(600)); | 
| +  mux_->AddSource(source1_); | 
| + | 
| +  MockBeginFrameObserver obs; | 
| +  mux_->AddObserver(&obs); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 100, 200, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300); | 
| + | 
| +  SEND_BEGIN_FRAME_USED(*source1_, 100, 200, 300); | 
| +  SEND_BEGIN_FRAME_DROP(*source1_, 400, 600, 300); | 
| +  SEND_BEGIN_FRAME_USED(*source1_, 700, 900, 300); | 
| +} | 
| + | 
| +TEST_F(BeginFrameSourceMultiplexerTest, MinimumIntervalWithMultipleSources) { | 
| +  mux_->SetMinimumInterval(base::TimeDelta::FromMicroseconds(150)); | 
| +  mux_->AddSource(source1_); | 
| +  mux_->AddSource(source2_); | 
| + | 
| +  MockBeginFrameObserver obs; | 
| +  mux_->AddObserver(&obs); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 400, 600, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 700, 900, 300); | 
| +  EXPECT_BEGIN_FRAME_USED(obs, 1050, 1250, 300); | 
| + | 
| +  mux_->SetActiveSource(source1_); | 
| +  SEND_BEGIN_FRAME_USED(*source1_, 400, 600, 300); | 
| +  SEND_BEGIN_FRAME_USED(*source1_, 700, 900, 300); | 
| + | 
| +  mux_->SetActiveSource(source2_); | 
| +  SEND_BEGIN_FRAME_DROP(*source2_, 750, 1050, 300); | 
| +  SEND_BEGIN_FRAME_USED(*source2_, 1050, 1250, 300); | 
| + | 
| +  mux_->SetActiveSource(source1_); | 
| +  SEND_BEGIN_FRAME_DROP(*source2_, 1100, 1400, 300); | 
| +} | 
| + | 
| +}  // namespace | 
| +}  // namespace cc | 
|  |