Chromium Code Reviews| Index: media/base/composite_filter_unittest.cc |
| diff --git a/media/base/composite_filter_unittest.cc b/media/base/composite_filter_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..5a529f521c5e9c13921e177aa5ad6355886e5fe9 |
| --- /dev/null |
| +++ b/media/base/composite_filter_unittest.cc |
| @@ -0,0 +1,809 @@ |
| +// Copyright (c) 2010 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 "media/base/composite_filter.h" |
| +#include "media/base/mock_filter_host.h" |
| +#include "media/base/mock_filters.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +using ::testing::_; |
| +using ::testing::InSequence; |
| +using ::testing::Return; |
| +using ::testing::SaveArg; |
| +using ::testing::StrictMock; |
| + |
| +namespace media { |
| + |
| +class CompositeFilterTest : public testing::Test { |
| + public: |
| + CompositeFilterTest(); |
| + virtual ~CompositeFilterTest(); |
| + |
| + // Sets up a new CompositeFilter in |composite_|, creates |filter_1_| and |
| + // |filter_2_|, and adds these filters to |composite_|. |
| + void SetupAndAdd2Filters(); |
| + |
| + // Helper enum that indicates what filter method to call. |
| + enum MethodToCall { |
| + PLAY, |
| + PAUSE, |
| + FLUSH, |
| + STOP, |
| + SEEK, |
| + }; |
| + |
| + // Helper method that adds a filter method call expectation based on the value |
| + // of |method_to_call|. |
| + // |
| + // |method_to_call| - Indicates which method we expect a call for. |
| + // |filter| - The MockFilter to add the expectation to. |
| + // |seek_time| - The time to pass to the Seek() call if |method_to_call| |
| + // equals SEEK. |
| + void ExpectFilterCall(MethodToCall method_to_call, MockFilter* filter, |
| + base::TimeDelta seek_time); |
| + |
| + // Helper method that calls a filter method based on the value of |
| + // |method_to_call|. |
| + // |
| + // |method_to_call| - Indicates which method to call. |
| + // |filter| - The Filter to make the method call on. |
| + // |seek_time| - The time to pass to the Seek() call if |method_to_call| |
| + // equals SEEK. |
| + // |callback| - The callback object to pass to the method. |
| + void DoFilterCall(MethodToCall method_to_call, Filter* filter, |
| + base::TimeDelta seek_time, |
| + FilterCallback* callback); |
| + |
| + // Creates an expectation sequence based on the value of method_to_call. |
| + // |
| + // |method_to_call| - Indicates which method we want a success sequence for. |
| + // |seek_time| - The time to pass in the Seek() call if |method_to_call| |
| + // equals SEEK. |
| + void ExpectSuccess(MethodToCall method_to_call, |
| + base::TimeDelta seek_time = base::TimeDelta()); |
| + |
| + // Issue a Play(), Pause(), Flush(), Stop(), or Seek() on the composite and |
| + // verify all the expected calls on the filters. |
| + void DoPlay(); |
| + void DoPause(); |
| + void DoFlush(); |
| + void DoStop(); |
| + void DoSeek(base::TimeDelta time); |
| + |
| + // Issue a Play(), Pause(), Flush(), or Seek() and expect the calls to fail |
| + // with a PIPELINE_ERROR_INVALID_STATE error. |
| + // |
| + // |method_to_call| - Indicates whick method to call. |
| + // |seek_time| - The time to pass to the Seek() call if |method_to_call| |
| + // equals SEEK. |
| + void ExpectInvalidStateFail(MethodToCall method_to_call, |
| + base::TimeDelta seek_time = base::TimeDelta()); |
| + |
| + // Run the callback stored in |filter_1_callback_|. |
| + void RunFilter1Callback(); |
| + |
| + // Run the callback stored in |filter_2_callback_|. |
| + void RunFilter2Callback(); |
| + |
| + protected: |
| + MessageLoop message_loop_; |
| + |
| + // The composite object being tested. |
| + scoped_refptr<CompositeFilter> composite_; |
| + |
| + // First filter added to the composite. |
| + scoped_refptr<StrictMock<MockFilter> > filter_1_; |
| + |
| + // Callback passed to |filter_1_| during last Play(), Pause(), Flush(), |
| + // Stop(), or Seek() call. |
| + FilterCallback* filter_1_callback_; |
| + |
| + // Second filter added to the composite. |
| + scoped_refptr<StrictMock<MockFilter> > filter_2_; |
| + |
| + // Callback passed to |filter_2_| during last Play(), Pause(), Flush(), |
| + // Stop(), or Seek() call. |
| + FilterCallback* filter_2_callback_; |
| + |
| + // FilterHost implementation passed to |composite_| via set_host(). |
| + scoped_ptr<StrictMock<MockFilterHost> > mock_filter_host_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(CompositeFilterTest); |
| +}; |
| + |
| +CompositeFilterTest::CompositeFilterTest() : |
| + composite_(new CompositeFilter(&message_loop_)), |
| + filter_1_callback_(NULL), |
| + filter_2_callback_(NULL), |
| + mock_filter_host_(new StrictMock<MockFilterHost>()) { |
| +} |
| + |
| +CompositeFilterTest::~CompositeFilterTest() {} |
| + |
| +void CompositeFilterTest::SetupAndAdd2Filters() { |
| + mock_filter_host_.reset(new StrictMock<MockFilterHost>()); |
| + composite_ = new CompositeFilter(&message_loop_); |
| + composite_->set_host(mock_filter_host_.get()); |
| + |
| + // Setup |filter_1_| and arrange for methods to set |
| + // |filter_1_callback_| when they are called. |
| + filter_1_ = new StrictMock<MockFilter>(); |
| + filter_1_callback_ = NULL; |
| + ON_CALL(*filter_1_, Play(_)) |
| + .WillByDefault(SaveArg<0>(&filter_1_callback_)); |
| + ON_CALL(*filter_1_, Pause(_)) |
| + .WillByDefault(SaveArg<0>(&filter_1_callback_)); |
| + ON_CALL(*filter_1_, Flush(_)) |
| + .WillByDefault(SaveArg<0>(&filter_1_callback_)); |
| + ON_CALL(*filter_1_, Stop(_)) |
| + .WillByDefault(SaveArg<0>(&filter_1_callback_)); |
| + ON_CALL(*filter_1_, Seek(_,_)) |
| + .WillByDefault(SaveArg<1>(&filter_1_callback_)); |
| + |
| + // Setup |filter_2_| and arrange for methods to set |
| + // |filter_2_callback_| when they are called. |
| + filter_2_ = new StrictMock<MockFilter>(); |
| + filter_2_callback_ = NULL; |
| + ON_CALL(*filter_2_, Play(_)) |
| + .WillByDefault(SaveArg<0>(&filter_2_callback_)); |
| + ON_CALL(*filter_2_, Pause(_)) |
| + .WillByDefault(SaveArg<0>(&filter_2_callback_)); |
| + ON_CALL(*filter_2_, Flush(_)) |
| + .WillByDefault(SaveArg<0>(&filter_2_callback_)); |
| + ON_CALL(*filter_2_, Stop(_)) |
| + .WillByDefault(SaveArg<0>(&filter_2_callback_)); |
| + ON_CALL(*filter_2_, Seek(_,_)) |
| + .WillByDefault(SaveArg<1>(&filter_2_callback_)); |
| + |
| + composite_->AddFilter(filter_1_); |
| + composite_->AddFilter(filter_2_); |
| +} |
| + |
| +void CompositeFilterTest::ExpectFilterCall(MethodToCall method_to_call, |
| + MockFilter* filter, |
| + base::TimeDelta seek_time) { |
| + switch(method_to_call) { |
| + case PLAY: |
| + EXPECT_CALL(*filter, Play(_)); |
| + break; |
| + case PAUSE: |
| + EXPECT_CALL(*filter, Pause(_)); |
| + break; |
| + case FLUSH: |
| + EXPECT_CALL(*filter, Flush(_)); |
| + break; |
| + case STOP: |
| + EXPECT_CALL(*filter, Stop(_)); |
| + break; |
| + case SEEK: |
| + EXPECT_CALL(*filter, Seek(seek_time, _)); |
| + break; |
| + }; |
| +} |
| + |
| +void CompositeFilterTest::DoFilterCall(MethodToCall method_to_call, |
| + Filter* filter, |
| + base::TimeDelta seek_time, |
| + FilterCallback* callback) { |
| + switch(method_to_call) { |
| + case PLAY: |
| + filter->Play(callback); |
| + break; |
| + case PAUSE: |
| + filter->Pause(callback); |
| + break; |
| + case FLUSH: |
| + filter->Flush(callback); |
| + break; |
| + case STOP: |
| + filter->Stop(callback); |
| + break; |
| + case SEEK: |
| + filter->Seek(seek_time, callback); |
| + break; |
| + }; |
| +} |
| + |
| +void CompositeFilterTest::ExpectSuccess(MethodToCall method_to_call, |
| + base::TimeDelta seek_time) { |
| + InSequence seq; |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + bool is_parallel_call = (method_to_call == FLUSH); |
| + |
| + ExpectFilterCall(method_to_call, filter_1_.get(), seek_time); |
| + |
| + if (is_parallel_call) { |
| + ExpectFilterCall(method_to_call, filter_2_.get(), seek_time); |
| + } |
| + |
| + // Make method call on the composite. |
| + DoFilterCall(method_to_call, composite_.get(), seek_time, |
| + mock_callback->NewCallback()); |
| + |
| + if (is_parallel_call) { |
| + // Make sure both filters have their callbacks set. |
| + EXPECT_TRUE(filter_1_callback_ != NULL); |
|
scherkus (not reviewing)
2010/12/20 20:36:21
you can even do without the != NULL part if you wa
|
| + EXPECT_TRUE(filter_2_callback_ != NULL); |
| + |
| + RunFilter1Callback(); |
| + } else { |
| + // Make sure that only |filter_1_| has its callback set. |
| + EXPECT_TRUE(filter_1_callback_ != NULL); |
| + EXPECT_EQ((FilterCallback*)NULL, filter_2_callback_); |
| + |
| + ExpectFilterCall(method_to_call, filter_2_.get(), seek_time); |
| + |
| + RunFilter1Callback(); |
| + |
| + // Verify that |filter_2_| was called by checking the callback pointer. |
| + EXPECT_TRUE(filter_2_callback_ != NULL); |
| + } |
| + |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + |
| + RunFilter2Callback(); |
| +} |
| + |
| +void CompositeFilterTest::DoPlay() { |
| + ExpectSuccess(PLAY); |
| +} |
| + |
| +void CompositeFilterTest::DoPause() { |
| + ExpectSuccess(PAUSE); |
| +} |
| + |
| +void CompositeFilterTest::DoFlush() { |
| + ExpectSuccess(FLUSH); |
| +} |
| + |
| +void CompositeFilterTest::DoStop() { |
| + ExpectSuccess(STOP); |
| +} |
| + |
| +void CompositeFilterTest::DoSeek(base::TimeDelta time) { |
| + ExpectSuccess(SEEK, time); |
| +} |
| + |
| +void CompositeFilterTest::ExpectInvalidStateFail(MethodToCall method_to_call, |
| + base::TimeDelta seek_time) { |
| + InSequence seq; |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + EXPECT_CALL(*mock_filter_host_, SetError(PIPELINE_ERROR_INVALID_STATE)) |
| + .WillOnce(Return()); |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + |
| + DoFilterCall(method_to_call, composite_, seek_time, |
| + mock_callback->NewCallback()); |
| + |
| + // Make sure that neither of the filters were called by |
| + // verifying that the callback pointers weren't set. |
| + EXPECT_EQ((FilterCallback*)NULL, filter_1_callback_); |
| + EXPECT_EQ((FilterCallback*)NULL, filter_2_callback_); |
| +} |
| + |
| +void CompositeFilterTest::RunFilter1Callback() { |
| + EXPECT_TRUE(filter_1_callback_ != NULL); |
| + FilterCallback* callback = filter_1_callback_; |
| + filter_1_callback_ = NULL; |
| + callback->Run(); |
| + delete callback; |
| +} |
| + |
| +void CompositeFilterTest::RunFilter2Callback() { |
| + EXPECT_TRUE(filter_2_callback_ != NULL); |
| + FilterCallback* callback = filter_2_callback_; |
| + filter_2_callback_ = NULL; |
| + callback->Run(); |
| + delete callback; |
| +} |
| + |
| +static base::Thread* NullThreadFactory(const char* thread_name) { |
| + return NULL; |
| +} |
| + |
| +// Test AddFilter() failure cases. |
| +TEST_F(CompositeFilterTest, TestAddFilterFailCases) { |
| + // Test adding a null pointer. |
| + EXPECT_FALSE(composite_->AddFilter(NULL)); |
| + |
| + scoped_refptr<StrictMock<MockFilter> > filter = |
| + new StrictMock<MockFilter>(true); |
| + EXPECT_EQ(NULL, filter->host()); |
| + EXPECT_EQ(NULL, filter->message_loop()); |
| + |
| + // Test failing because set_host() hasn't been called yet. |
| + EXPECT_FALSE(composite_->AddFilter(filter)); |
| + |
| + // Test thread creation failure. |
| + composite_ = new CompositeFilter(&message_loop_, &NullThreadFactory); |
| + composite_->set_host(mock_filter_host_.get()); |
| + EXPECT_FALSE(composite_->AddFilter(filter)); |
| + EXPECT_EQ(NULL, filter->host()); |
| + EXPECT_EQ(NULL, filter->message_loop()); |
| +} |
| + |
| +// Test successful AddFilter() cases. |
| +TEST_F(CompositeFilterTest, TestAddFilter) { |
| + composite_->set_host(mock_filter_host_.get()); |
| + |
| + // Add a filter that doesn't require a message loop. |
| + scoped_refptr<StrictMock<MockFilter> > filter = new StrictMock<MockFilter>(); |
| + EXPECT_EQ(NULL, filter->host()); |
| + EXPECT_EQ(NULL, filter->message_loop()); |
| + |
| + EXPECT_TRUE(composite_->AddFilter(filter)); |
| + |
| + EXPECT_TRUE(filter->host() != NULL); |
| + EXPECT_EQ(NULL, filter->message_loop()); |
| + |
| + // Add a filter that requires a message loop. |
| + scoped_refptr<StrictMock<MockFilter> > filter_2 = |
| + new StrictMock<MockFilter>(true); |
| + |
| + EXPECT_EQ(NULL, filter_2->host()); |
| + EXPECT_EQ(NULL, filter_2->message_loop()); |
| + |
| + EXPECT_TRUE(composite_->AddFilter(filter_2)); |
| + |
| + EXPECT_TRUE(filter_2->host() != NULL); |
| + EXPECT_TRUE(filter_2->message_loop() != NULL); |
| +} |
| + |
| +static bool g_thread_cleanup_called_ = false; |
| +class CompositeFilterThread : public base::Thread { |
| + public: |
| + CompositeFilterThread(const char* name) : base::Thread(name) {} |
| + virtual void CleanUp() { |
| + g_thread_cleanup_called_ = true; |
| + base::Thread::CleanUp(); |
| + } |
| +}; |
| + |
| +TEST_F(CompositeFilterTest, TestPlay) { |
| + InSequence sequence; |
| + |
| + SetupAndAdd2Filters(); |
| + |
| + // Verify successful call to Play(). |
| + DoPlay(); |
| + |
| + // At this point we are now in the kPlaying state. |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + // Try calling Play() again to make sure that we simply get a callback. |
| + // We are already in the Play() state so there is no point calling the |
| + // filters. |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + |
| + composite_->Play(mock_callback->NewCallback()); |
| + |
| + // Verify that neither of the filter callbacks were set. |
| + EXPECT_EQ((FilterCallback*)NULL, filter_1_callback_); |
| + EXPECT_EQ((FilterCallback*)NULL, filter_2_callback_); |
| + |
| + // Stop playback. |
| + DoStop(); |
| + |
| + // At this point we should be in the kStopped state. |
| + |
| + // Try calling Stop() again to make sure neither filter is called. |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + |
| + composite_->Stop(mock_callback->NewCallback()); |
| + |
| + // Verify that neither of the filter callbacks were set. |
| + EXPECT_EQ((FilterCallback*)NULL, filter_1_callback_); |
| + EXPECT_EQ((FilterCallback*)NULL, filter_2_callback_); |
| + |
| + // Try calling Play() again to make sure we get an error. |
| + ExpectInvalidStateFail(PLAY); |
| +} |
| + |
| +// Test errors in the middle of a serial call sequence like Play(). |
| +TEST_F(CompositeFilterTest, TestPlayErrors) { |
| + InSequence sequence; |
| + |
| + SetupAndAdd2Filters(); |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + EXPECT_CALL(*filter_1_, Play(_)); |
| + |
| + // Call Play() on the composite. |
| + composite_->Play(mock_callback->NewCallback()); |
| + |
| + EXPECT_CALL(*filter_2_, Play(_)); |
| + |
| + // Run callback to indicate that |filter_1_|'s Play() has completed. |
| + RunFilter1Callback(); |
| + |
| + // At this point Play() has been called on |filter_2_|. Simulate an |
| + // error by calling SetError() on its FilterHost interface. |
| + filter_2_->host()->SetError(PIPELINE_ERROR_OUT_OF_MEMORY); |
| + |
| + // Expect error to be reported and "play done" callback to be called. |
| + EXPECT_CALL(*mock_filter_host_, SetError(PIPELINE_ERROR_OUT_OF_MEMORY)); |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + |
| + // Run callback to indicate that |filter_2_|'s Play() has completed. |
| + RunFilter2Callback(); |
| + |
| + // Verify that Play/Pause/Flush/Seek fail now that an error occured. |
| + ExpectInvalidStateFail(PLAY); |
| + ExpectInvalidStateFail(PAUSE); |
| + ExpectInvalidStateFail(FLUSH); |
| + ExpectInvalidStateFail(SEEK); |
| + |
| + // Make sure you can still Stop(). |
| + DoStop(); |
| +} |
| + |
| +TEST_F(CompositeFilterTest, TestPause) { |
| + InSequence sequence; |
| + |
| + SetupAndAdd2Filters(); |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + // Try calling Pause() to make sure we get an error because we aren't in |
| + // the playing state. |
| + ExpectInvalidStateFail(PAUSE); |
| + |
| + // Transition to playing state. |
| + DoPlay(); |
| + |
| + // Issue a successful Pause(). |
| + DoPause(); |
| + |
| + // At this point we are paused. |
| + |
| + // Try calling Pause() again to make sure that the filters aren't called |
| + // because we are already in the paused state. |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + |
| + composite_->Pause(mock_callback->NewCallback()); |
| + |
| + // Verify that neither of the filter callbacks were set. |
| + EXPECT_EQ((FilterCallback*)NULL, filter_1_callback_); |
| + EXPECT_EQ((FilterCallback*)NULL, filter_2_callback_); |
| + |
| + // Verify that we can transition pack to the play state. |
| + DoPlay(); |
| + |
| + // Go back to the pause state. |
| + DoPause(); |
| + |
| + // Transition to the stop state. |
| + DoStop(); |
| + |
| + // Try calling Pause() to make sure we get an error because we aren't in |
| + // the playing state. |
| + ExpectInvalidStateFail(PAUSE); |
| +} |
| + |
| +// Test errors in the middle of a serial call sequence like Pause(). |
| +TEST_F(CompositeFilterTest, TestPauseErrors) { |
| + InSequence sequence; |
| + |
| + SetupAndAdd2Filters(); |
| + |
| + DoPlay(); |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + EXPECT_CALL(*filter_1_, Pause(_)); |
| + |
| + // Call Pause() on the composite. |
| + composite_->Pause(mock_callback->NewCallback()); |
| + |
| + // Simulate an error by calling SetError() on |filter_1_|'s FilterHost |
| + // interface. |
| + filter_1_->host()->SetError(PIPELINE_ERROR_OUT_OF_MEMORY); |
| + |
| + // Expect error to be reported and "pause done" callback to be called. |
| + EXPECT_CALL(*mock_filter_host_, SetError(PIPELINE_ERROR_OUT_OF_MEMORY)); |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + |
| + RunFilter1Callback(); |
| + |
| + // Make sure |filter_2_callback_| was not set. |
| + EXPECT_EQ((FilterCallback*)NULL, filter_2_callback_); |
| + |
| + // Verify that Play/Pause/Flush/Seek fail now that an error occured. |
| + ExpectInvalidStateFail(PLAY); |
| + ExpectInvalidStateFail(PAUSE); |
| + ExpectInvalidStateFail(FLUSH); |
| + ExpectInvalidStateFail(SEEK); |
| + |
| + // Make sure you can still Stop(). |
| + DoStop(); |
| +} |
| + |
| +TEST_F(CompositeFilterTest, TestFlush) { |
| + InSequence sequence; |
| + |
| + SetupAndAdd2Filters(); |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + // Make sure Flush() works before calling Play(). |
| + DoFlush(); |
| + |
| + // Transition to playing state. |
| + DoPlay(); |
| + |
| + // Call Flush() to make sure we get an error because we are in |
| + // the playing state. |
| + ExpectInvalidStateFail(FLUSH); |
| + |
| + // Issue a successful Pause(). |
| + DoPause(); |
| + |
| + // Make sure Flush() works after pausing. |
| + DoFlush(); |
| + |
| + // Verify that we can transition back to the play state. |
| + DoPlay(); |
| + |
| + // Transition to the stop state. |
| + DoStop(); |
| + |
| + // Try calling Flush() to make sure we get an error because we are stopped. |
| + ExpectInvalidStateFail(FLUSH); |
| +} |
| + |
| +// Test errors in the middle of a parallel call sequence like Flush(). |
| +TEST_F(CompositeFilterTest, TestFlushErrors) { |
| + InSequence sequence; |
| + |
| + SetupAndAdd2Filters(); |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + EXPECT_CALL(*filter_1_, Flush(_)); |
| + EXPECT_CALL(*filter_2_, Flush(_)); |
| + |
| + // Call Flush() on the composite. |
| + composite_->Flush(mock_callback->NewCallback()); |
| + |
| + // Simulate an error by calling SetError() on |filter_1_|'s FilterHost |
| + // interface. |
| + filter_1_->host()->SetError(PIPELINE_ERROR_OUT_OF_MEMORY); |
| + |
| + RunFilter1Callback(); |
| + |
| + // Expect error to be reported and "pause done" callback to be called. |
| + EXPECT_CALL(*mock_filter_host_, SetError(PIPELINE_ERROR_OUT_OF_MEMORY)); |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + |
| + RunFilter2Callback(); |
| + |
| + // Verify that Play/Pause/Flush/Seek fail now that an error occured. |
| + ExpectInvalidStateFail(PLAY); |
| + ExpectInvalidStateFail(PAUSE); |
| + ExpectInvalidStateFail(FLUSH); |
| + ExpectInvalidStateFail(SEEK); |
| + |
| + // Make sure you can still Stop(). |
| + DoStop(); |
| +} |
| + |
| +TEST_F(CompositeFilterTest, TestSeek) { |
| + InSequence sequence; |
| + |
| + SetupAndAdd2Filters(); |
| + |
| + // Verify that seek is allowed to be called before a Play() call. |
| + DoSeek(base::TimeDelta::FromSeconds(5)); |
| + |
| + // Verify we can issue a Play() after the Seek(). |
| + DoPlay(); |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + // Try calling Seek() while playing to make sure we get an error. |
| + ExpectInvalidStateFail(SEEK); |
| + |
| + // Transition to paused state. |
| + DoPause(); |
| + |
| + // Verify that seek is allowed after pausing. |
| + DoSeek(base::TimeDelta::FromSeconds(5)); |
| + |
| + // Verify we can still play again. |
| + DoPlay(); |
| + |
| + // Stop playback. |
| + DoStop(); |
| + |
| + // Try calling Seek() to make sure we get an error. |
| + ExpectInvalidStateFail(SEEK); |
| +} |
| + |
| +TEST_F(CompositeFilterTest, TestStop) { |
| + InSequence sequence; |
| + |
| + // Test Stop() before any other call. |
| + SetupAndAdd2Filters(); |
| + DoStop(); |
| + |
| + // Test error during Stop() sequence. |
| + SetupAndAdd2Filters(); |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + EXPECT_CALL(*filter_1_, Stop(_)); |
| + |
| + composite_->Stop(mock_callback->NewCallback()); |
| + |
| + // Have |filter_1_| signal an error. |
| + filter_1_->host()->SetError(PIPELINE_ERROR_READ); |
| + |
| + EXPECT_CALL(*filter_2_, Stop(_)); |
| + |
| + RunFilter1Callback(); |
| + |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + |
| + RunFilter2Callback(); |
| +} |
| + |
| +// Test stopping in the middle of a serial call sequence. |
| +TEST_F(CompositeFilterTest, TestStopWhilePlayPending) { |
| + InSequence sequence; |
| + |
| + SetupAndAdd2Filters(); |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>()); |
| + |
| + EXPECT_CALL(*filter_1_, Play(_)); |
| + |
| + composite_->Play(mock_callback->NewCallback()); |
| + |
| + // Note: Play() is pending on |filter_1_| right now. |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback_2( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + EXPECT_CALL(*mock_callback, OnCallbackDestroyed()); |
| + |
| + composite_->Stop(mock_callback_2->NewCallback()); |
| + |
| + EXPECT_CALL(*filter_1_, Stop(_)); |
| + |
| + // Run |filter_1_|'s callback again to indicate Play() has completed. |
| + RunFilter1Callback(); |
| + |
| + EXPECT_CALL(*filter_2_, Stop(_)); |
| + |
| + // Run |filter_1_|'s callback again to indicate Stop() has completed. |
| + RunFilter1Callback(); |
| + |
| + EXPECT_CALL(*mock_callback_2, OnFilterCallback()); |
| + |
| + // Run |filter_2_|'s callback to indicate Stop() has completed. |
| + RunFilter2Callback(); |
| +} |
| + |
| +// Test stopping in the middle of a parallel call sequence. |
| +TEST_F(CompositeFilterTest, TestStopWhileFlushPending) { |
| + InSequence sequence; |
| + |
| + SetupAndAdd2Filters(); |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>()); |
| + |
| + EXPECT_CALL(*filter_1_, Flush(_)); |
| + EXPECT_CALL(*filter_2_, Flush(_)); |
| + |
| + composite_->Flush(mock_callback->NewCallback()); |
| + |
| + // Note: |filter_1_| and |filter_2_| have pending Flush() calls at this point. |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback_2( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + EXPECT_CALL(*mock_callback, OnCallbackDestroyed()); |
| + |
| + composite_->Stop(mock_callback_2->NewCallback()); |
| + |
| + // Run callback to indicate that |filter_1_|'s Flush() has completed. |
| + RunFilter1Callback(); |
| + |
| + EXPECT_CALL(*filter_1_, Stop(_)); |
| + |
| + // Run callback to indicate that |filter_2_|'s Flush() has completed. |
| + RunFilter2Callback(); |
| + |
| + EXPECT_CALL(*filter_2_, Stop(_)); |
| + |
| + // Run callback to indicate that |filter_1_|'s Stop() has completed. |
| + RunFilter1Callback(); |
| + |
| + EXPECT_CALL(*mock_callback_2, OnFilterCallback()); |
| + |
| + // Run callback to indicate that |filter_2_|'s Stop() has completed. |
| + RunFilter2Callback(); |
| +} |
| + |
| +TEST_F(CompositeFilterTest, TestErrorWhilePlaying) { |
| + InSequence sequence; |
| + |
| + SetupAndAdd2Filters(); |
| + |
| + // Simulate an error on |filter_2_| while in kCreated state. This |
| + // can happen if an error occurs during filter initialization. |
| + EXPECT_CALL(*mock_filter_host_, SetError(PIPELINE_ERROR_OUT_OF_MEMORY)); |
| + filter_2_->host()->SetError(PIPELINE_ERROR_OUT_OF_MEMORY); |
| + |
| + DoPlay(); |
| + |
| + // Simulate an error on |filter_2_| while playing. |
| + EXPECT_CALL(*mock_filter_host_, SetError(PIPELINE_ERROR_OUT_OF_MEMORY)); |
| + filter_2_->host()->SetError(PIPELINE_ERROR_OUT_OF_MEMORY); |
| + |
| + DoPause(); |
| + |
| + // Simulate an error on |filter_2_| while paused. |
| + EXPECT_CALL(*mock_filter_host_, SetError(PIPELINE_ERROR_NETWORK)); |
| + filter_2_->host()->SetError(PIPELINE_ERROR_NETWORK); |
| + |
| + DoStop(); |
| + |
| + // Verify that errors are not passed to |mock_filter_host_| |
| + // after Stop() has been called. |
| + filter_2_->host()->SetError(PIPELINE_ERROR_NETWORK); |
| +} |
| + |
| +// Make sure that state transitions act as expected even |
| +// if the composite doesn't contain any filters. |
| +TEST_F(CompositeFilterTest, TestEmptyComposite) { |
| + InSequence sequence; |
| + |
| + composite_->set_host(mock_filter_host_.get()); |
| + |
| + scoped_ptr<StrictMock<MockFilterCallback> > mock_callback( |
| + new StrictMock<MockFilterCallback>(false)); |
| + |
| + // Issue a Play() and expect no errors. |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + composite_->Play(mock_callback->NewCallback()); |
| + |
| + // Issue a Pause() and expect no errors. |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + composite_->Pause(mock_callback->NewCallback()); |
| + |
| + // Issue a Flush() and expect no errors. |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + composite_->Flush(mock_callback->NewCallback()); |
| + |
| + // Issue a Seek() and expect no errors. |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + composite_->Seek(base::TimeDelta::FromSeconds(5), |
| + mock_callback->NewCallback()); |
| + |
| + // Issue a Play() and expect no errors. |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + composite_->Play(mock_callback->NewCallback()); |
| + |
| + // Issue a Stop() and expect no errors. |
| + EXPECT_CALL(*mock_callback, OnFilterCallback()); |
| + composite_->Stop(mock_callback->NewCallback()); |
| +} |
| + |
| +} // namespace media |