| Index: media/filters/pipeline_controller_unittest.cc
|
| diff --git a/media/filters/pipeline_controller_unittest.cc b/media/filters/pipeline_controller_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..5f3a5b2749cef9c2644cfa4879151c06d62c00d4
|
| --- /dev/null
|
| +++ b/media/filters/pipeline_controller_unittest.cc
|
| @@ -0,0 +1,168 @@
|
| +// Copyright (c) 2016 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 "base/bind.h"
|
| +#include "base/bind_helpers.h"
|
| +#include "base/logging.h"
|
| +#include "base/macros.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/time/time.h"
|
| +#include "media/base/pipeline.h"
|
| +#include "media/filters/pipeline_controller.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using ::testing::_;
|
| +using ::testing::Mock;
|
| +using ::testing::NiceMock;
|
| +using ::testing::SaveArg;
|
| +
|
| +namespace media {
|
| +
|
| +ACTION_TEMPLATE(RunCallback,
|
| + HAS_1_TEMPLATE_PARAMS(int, k),
|
| + AND_1_VALUE_PARAMS(p0)) {
|
| + return ::std::tr1::get<k>(args).Run(p0);
|
| +}
|
| +
|
| +class MockPipeline : public Pipeline {
|
| + public:
|
| + MockPipeline() {}
|
| +
|
| + virtual ~MockPipeline() {}
|
| +
|
| + // Start() cannot be mocked due to scoped_ptr. Instead it forwards to a
|
| + // version that can.
|
| + MOCK_METHOD10(Start,
|
| + void(Demuxer*,
|
| + scoped_ptr<Renderer>*,
|
| + const base::Closure&,
|
| + const PipelineStatusCB&,
|
| + const PipelineStatusCB&,
|
| + const PipelineMetadataCB&,
|
| + const BufferingStateCB&,
|
| + const base::Closure&,
|
| + const AddTextTrackCB&,
|
| + const base::Closure&));
|
| +
|
| + void Start(Demuxer* demuxer,
|
| + scoped_ptr<Renderer> renderer,
|
| + const base::Closure& ended_cb,
|
| + const PipelineStatusCB& error_cb,
|
| + const PipelineStatusCB& seek_cb,
|
| + const PipelineMetadataCB& metadata_cb,
|
| + const BufferingStateCB& buffering_state_cb,
|
| + const base::Closure& duration_change_cb,
|
| + const AddTextTrackCB& add_text_track_cb,
|
| + const base::Closure& waiting_for_decryption_key_cb) override {
|
| + Start(demuxer, &renderer, ended_cb, error_cb, seek_cb, metadata_cb,
|
| + buffering_state_cb, duration_change_cb, add_text_track_cb,
|
| + waiting_for_decryption_key_cb);
|
| + }
|
| +
|
| + MOCK_METHOD1(Stop, void(const base::Closure&));
|
| + MOCK_METHOD2(Seek, void(base::TimeDelta, const PipelineStatusCB&));
|
| + MOCK_METHOD1(Suspend, void(const PipelineStatusCB&));
|
| +
|
| + // Resume() cannot be mocked due to scoped_ptr. Instead it forwards to a
|
| + // version that can.
|
| + MOCK_METHOD3(Resume,
|
| + void(scoped_ptr<Renderer>*,
|
| + base::TimeDelta,
|
| + const PipelineStatusCB&));
|
| +
|
| + void Resume(scoped_ptr<Renderer> renderer,
|
| + base::TimeDelta timestamp,
|
| + const PipelineStatusCB& seek_cb) override {
|
| + Resume(&renderer, timestamp, seek_cb);
|
| + }
|
| +
|
| + // TODO(sandersd): It would be helpful if this always returned true once the
|
| + // start callback was called (until Stop()).
|
| + MOCK_CONST_METHOD0(IsRunning, bool());
|
| +
|
| + // TODO(sandersd): These should be regular get/set implementations.
|
| + MOCK_CONST_METHOD0(GetPlaybackRate, double());
|
| + MOCK_METHOD1(SetPlaybackRate, void(double));
|
| + MOCK_CONST_METHOD0(GetVolume, float());
|
| + MOCK_METHOD1(SetVolume, void(float));
|
| +
|
| + // TODO(sandersd): Some sort of help would be useful for configuring these.
|
| + MOCK_CONST_METHOD0(GetMediaTime, base::TimeDelta());
|
| + MOCK_CONST_METHOD0(GetBufferedTimeRanges, Ranges<base::TimeDelta>());
|
| + MOCK_CONST_METHOD0(GetMediaDuration, base::TimeDelta());
|
| + MOCK_METHOD0(DidLoadingProgress, bool());
|
| + MOCK_CONST_METHOD0(GetStatistics, PipelineStatistics());
|
| +
|
| + MOCK_METHOD2(SetCdm, void(CdmContext*, const CdmAttachedCB&));
|
| +};
|
| +
|
| +class PipelineControllerTest : public ::testing::Test {
|
| + public:
|
| + PipelineControllerTest()
|
| + : pipeline_controller_(&pipeline_,
|
| + base::Bind(&PipelineControllerTest::CreateRenderer,
|
| + base::Unretained(this)),
|
| + base::Bind(&PipelineControllerTest::OnSeeked,
|
| + base::Unretained(this)),
|
| + base::Bind(&PipelineControllerTest::OnSuspended,
|
| + base::Unretained(this)),
|
| + base::Bind(&PipelineControllerTest::OnError,
|
| + base::Unretained(this))) {}
|
| +
|
| + ~PipelineControllerTest() override {}
|
| +
|
| + void StartPipeline(ChunkDemuxer* chunk_demuxer) {
|
| + // Everything other than |chunk_demuxer| is null since there is no reason
|
| + // for MockPipeline to call them.
|
| + pipeline_controller_.Start(
|
| + chunk_demuxer, nullptr, false, base::Closure(), PipelineMetadataCB(),
|
| + BufferingStateCB(), base::Closure(), AddTextTrackCB(), base::Closure());
|
| + }
|
| +
|
| + void StopPipeline() {}
|
| +
|
| + protected:
|
| + scoped_ptr<Renderer> CreateRenderer() { return scoped_ptr<Renderer>(); }
|
| +
|
| + void OnSeeked(bool time_updated) {}
|
| +
|
| + void OnSuspended() {}
|
| +
|
| + void OnError(PipelineStatus status) { NOTREACHED(); }
|
| +
|
| + MockPipeline pipeline_;
|
| + PipelineController pipeline_controller_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(PipelineControllerTest);
|
| +};
|
| +
|
| +TEST_F(PipelineControllerTest, PendingSuspend) {
|
| + // Immediately complete Pipline startup.
|
| + EXPECT_CALL(pipeline_, Start(_, _, _, _, _, _, _, _, _, _))
|
| + .WillOnce(RunCallback<4>(PIPELINE_OK));
|
| + StartPipeline(nullptr);
|
| +
|
| + Mock::VerifyAndClear(&pipeline_);
|
| + EXPECT_TRUE(pipeline_controller_.IsStable());
|
| +
|
| + // Start a seek, but do not complete it immediately.
|
| + base::TimeDelta seek_time = base::TimeDelta::FromSeconds(5);
|
| + PipelineStatusCB seek_cb;
|
| + EXPECT_CALL(pipeline_, Seek(seek_time, _)).WillOnce(SaveArg<1>(&seek_cb));
|
| + pipeline_controller_.Seek(seek_time, true);
|
| +
|
| + Mock::VerifyAndClear(&pipeline_);
|
| + EXPECT_FALSE(pipeline_controller_.IsStable());
|
| +
|
| + // Schedule a suspend. (It shouldn't happen yet.)
|
| + pipeline_controller_.Suspend();
|
| +
|
| + // Complete the seek; the suspend should trigger.
|
| + EXPECT_CALL(pipeline_, Suspend(_));
|
| + seek_cb.Run(PIPELINE_OK);
|
| +}
|
| +
|
| +} // namespace media
|
|
|