diff options
author | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-10 20:47:51 +0000 |
---|---|---|
committer | scherkus@chromium.org <scherkus@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-07-10 20:47:51 +0000 |
commit | ba650a35365f11389eebe5b5325d1ad0e9a69b8e (patch) | |
tree | 80089187df282aec574b927ca720449b4bff15a0 /media/base | |
parent | fe9d5d06dd4acbd1df3f828207d7ebfa1a245279 (diff) | |
download | chromium_src-ba650a35365f11389eebe5b5325d1ad0e9a69b8e.zip chromium_src-ba650a35365f11389eebe5b5325d1ad0e9a69b8e.tar.gz chromium_src-ba650a35365f11389eebe5b5325d1ad0e9a69b8e.tar.bz2 |
Converted remaining tests to use gmock and deleted all old mocking code.
The most important part was refactoring PipelineImpl tests in preparation for message loop injection. The old mocks just did not work *at all* with my message loop injection patch.
BUG=16008
TEST=media_unittests should pass and not flake out
Review URL: http://codereview.chromium.org/149423
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@20412 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/base')
-rw-r--r-- | media/base/mock_ffmpeg.cc | 41 | ||||
-rw-r--r-- | media/base/mock_ffmpeg.h | 8 | ||||
-rw-r--r-- | media/base/mock_filters.h | 51 | ||||
-rw-r--r-- | media/base/mock_media_filters.h | 656 | ||||
-rw-r--r-- | media/base/pipeline_impl_unittest.cc | 248 | ||||
-rw-r--r-- | media/base/video_frame_impl_unittest.cc | 50 |
6 files changed, 298 insertions, 756 deletions
diff --git a/media/base/mock_ffmpeg.cc b/media/base/mock_ffmpeg.cc index 054f996..562aff2 100644 --- a/media/base/mock_ffmpeg.cc +++ b/media/base/mock_ffmpeg.cc @@ -7,12 +7,36 @@ #include "base/logging.h" #include "media/filters/ffmpeg_common.h" +using ::testing::_; +using ::testing::AtMost; +using ::testing::DoAll; +using ::testing::Return; +using ::testing::SaveArg; + namespace media { MockFFmpeg* MockFFmpeg::instance_ = NULL; +URLProtocol* MockFFmpeg::protocol_ = NULL; MockFFmpeg::MockFFmpeg() : outstanding_packets_(0) { + // If we haven't assigned our static copy of URLProtocol, set up expectations + // to catch the URLProtocol registered when the singleton instance of + // FFmpegGlue is created. + // + // TODO(scherkus): this feels gross and I need to think of a way to better + // inject/mock singletons. + if (!protocol_) { + EXPECT_CALL(*this, AVCodecInit()) + .Times(AtMost(1)) + .WillOnce(Return()); + EXPECT_CALL(*this, AVRegisterProtocol(_)) + .Times(AtMost(1)) + .WillOnce(DoAll(SaveArg<0>(&protocol_), Return(0))); + EXPECT_CALL(*this, AVRegisterAll()) + .Times(AtMost(1)) + .WillOnce(Return()); + } } MockFFmpeg::~MockFFmpeg() { @@ -40,6 +64,11 @@ MockFFmpeg* MockFFmpeg::get() { } // static +URLProtocol* MockFFmpeg::protocol() { + return protocol_; +} + +// static void MockFFmpeg::DestructPacket(AVPacket* packet) { delete [] packet->data; packet->data = NULL; @@ -49,6 +78,18 @@ void MockFFmpeg::DestructPacket(AVPacket* packet) { // FFmpeg stubs that delegate to the FFmpegMock instance. extern "C" { +void avcodec_init() { + media::MockFFmpeg::get()->AVCodecInit(); +} + +int av_register_protocol(URLProtocol* protocol) { + return media::MockFFmpeg::get()->AVRegisterProtocol(protocol); +} + +void av_register_all() { + media::MockFFmpeg::get()->AVRegisterAll(); +} + AVCodec* avcodec_find_decoder(enum CodecID id) { return media::MockFFmpeg::get()->AVCodecFindDecoder(id); } diff --git a/media/base/mock_ffmpeg.h b/media/base/mock_ffmpeg.h index 3afdef9..4ba38fc 100644 --- a/media/base/mock_ffmpeg.h +++ b/media/base/mock_ffmpeg.h @@ -16,6 +16,10 @@ class MockFFmpeg { MockFFmpeg(); virtual ~MockFFmpeg(); + MOCK_METHOD0(AVCodecInit, void()); + MOCK_METHOD1(AVRegisterProtocol, int(URLProtocol* protocol)); + MOCK_METHOD0(AVRegisterAll, void()); + MOCK_METHOD1(AVCodecFindDecoder, AVCodec*(enum CodecID id)); MOCK_METHOD2(AVCodecOpen, int(AVCodecContext* avctx, AVCodec* codec)); MOCK_METHOD1(AVCodecClose, int(AVCodecContext* avctx)); @@ -51,6 +55,9 @@ class MockFFmpeg { static void set(MockFFmpeg* instance); static MockFFmpeg* get(); + // Returns the URLProtocol registered by the FFmpegGlue singleton. + static URLProtocol* protocol(); + // AVPacket destructor for packets allocated by av_new_packet(). static void DestructPacket(AVPacket* packet); @@ -60,6 +67,7 @@ class MockFFmpeg { private: static MockFFmpeg* instance_; + static URLProtocol* protocol_; // Tracks the number of packets allocated by calls to av_read_frame() and // av_free_packet(). We crash the unit test if this is not zero at time of diff --git a/media/base/mock_filters.h b/media/base/mock_filters.h index bef46a7..bffba6f 100644 --- a/media/base/mock_filters.h +++ b/media/base/mock_filters.h @@ -19,6 +19,27 @@ namespace media { +// Use this template to test for object destruction by setting expectations on +// the method OnDestroy(). +// +// TODO(scherkus): not sure about the naming... perhaps contribute this back +// to gmock itself! +template<class MockClass> +class Destroyable : public MockClass { + public: + Destroyable() {} + + MOCK_METHOD0(OnDestroy, void()); + + protected: + virtual ~Destroyable() { + OnDestroy(); + } + + private: + DISALLOW_COPY_AND_ASSIGN(Destroyable); +}; + class MockDataSource : public DataSource { public: MockDataSource() {} @@ -71,6 +92,12 @@ class MockDemuxerStream : public DemuxerStream { public: MockDemuxerStream() {} + // Sets the mime type of this object's media format, which is usually checked + // to determine the type of decoder to create. + explicit MockDemuxerStream(const std::string& mime_type) { + media_format_.SetAsString(MediaFormat::kMimeType, mime_type); + } + // DemuxerStream implementation. const MediaFormat& media_format() { return media_format_; } MOCK_METHOD1(Read, void(Callback1<Buffer*>::Type* read_callback)); @@ -175,7 +202,8 @@ class MockAudioRenderer : public AudioRenderer { class MockFilterFactory : public FilterFactory { public: MockFilterFactory() - : data_source_(new MockDataSource()), + : creation_successful_(true), + data_source_(new MockDataSource()), demuxer_(new MockDemuxer()), video_decoder_(new MockVideoDecoder()), audio_decoder_(new MockAudioDecoder()), @@ -185,6 +213,11 @@ class MockFilterFactory : public FilterFactory { virtual ~MockFilterFactory() {} + // Controls whether the Create() method is successful or not. + void set_creation_successful(bool creation_successful) { + creation_successful_ = creation_successful; + } + // Mock accessors. MockDataSource* data_source() const { return data_source_; } MockDemuxer* demuxer() const { return demuxer_; } @@ -195,6 +228,10 @@ class MockFilterFactory : public FilterFactory { protected: MediaFilter* Create(FilterType filter_type, const MediaFormat& media_format) { + if (!creation_successful_) { + return NULL; + } + switch (filter_type) { case FILTER_DATA_SOURCE: return data_source_; @@ -215,6 +252,7 @@ class MockFilterFactory : public FilterFactory { } private: + bool creation_successful_; scoped_refptr<MockDataSource> data_source_; scoped_refptr<MockDemuxer> demuxer_; scoped_refptr<MockVideoDecoder> video_decoder_; @@ -225,6 +263,17 @@ class MockFilterFactory : public FilterFactory { DISALLOW_COPY_AND_ASSIGN(MockFilterFactory); }; +// Helper gmock action that calls InitializationComplete() on behalf of the +// provided filter. +ACTION_P(InitializationComplete, filter) { + filter->host()->InitializationComplete(); +} + +// Helper gmock action that calls Error() on behalf of the provided filter. +ACTION_P2(Error, filter, error) { + filter->host()->Error(error); +} + } // namespace media #endif // MEDIA_BASE_MOCK_FILTERS_H_ diff --git a/media/base/mock_media_filters.h b/media/base/mock_media_filters.h deleted file mode 100644 index 698815f..0000000 --- a/media/base/mock_media_filters.h +++ /dev/null @@ -1,656 +0,0 @@ -// Copyright (c) 2009 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. -// -// TODO(ajwong): This whole file is deprecated in favor or gmock style mocks. -// The deprecated classes have been moved into the old_mocks to avoid colliding -// with the newer mock classes. Once all the unittests have been migrated, this -// should be deleted. - -#ifndef MEDIA_BASE_MOCK_MEDIA_FILTERS_H_ -#define MEDIA_BASE_MOCK_MEDIA_FILTERS_H_ - -#include <string> - -#include "base/scoped_ptr.h" -#include "base/waitable_event.h" -#include "media/base/buffers.h" -#include "media/base/factory.h" -#include "media/base/filter_host.h" -#include "media/base/filters.h" -#include "media/base/media_format.h" -#include "media/base/pipeline.h" -#include "media/base/video_frame_impl.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace media { - -namespace old_mocks { - -// Behaviors for MockDataSource filter. -enum MockDataSourceBehavior { - MOCK_DATA_SOURCE_NORMAL_INIT, - MOCK_DATA_SOURCE_NEVER_INIT, - MOCK_DATA_SOURCE_URL_ERROR_IN_INIT, - MOCK_DATA_SOURCE_INIT_RETURN_FALSE, -}; - - -// This class is used by all of the mock filters to change the configuration -// of the desired pipeline. The test using this must ensure that the lifetime -// of the object is at least as long as the lifetime of the filters, as this -// is typically allocated on the stack. -struct MockFilterConfig { - MockFilterConfig() - : create_filter(true), - data_source_behavior(MOCK_DATA_SOURCE_NORMAL_INIT), - data_source_value('!'), - has_video(true), - video_width(1280u), - video_height(720u), - video_surface_format(VideoSurface::YV12), - has_audio(true), - compressed_audio_mime_type(mime_type::kAACAudio), - uncompressed_audio_mime_type(mime_type::kUncompressedAudio), - compressed_video_mime_type(mime_type::kH264AnnexB), - uncompressed_video_mime_type(mime_type::kUncompressedVideo), - frame_duration(base::TimeDelta::FromMicroseconds(33333)), - media_duration(base::TimeDelta::FromSeconds(5)), - media_total_bytes(media_duration.InMilliseconds() * 250) { - } - - bool create_filter; - MockDataSourceBehavior data_source_behavior; - char data_source_value; - bool has_video; - size_t video_width; - size_t video_height; - VideoSurface::Format video_surface_format; - bool has_audio; - std::string compressed_audio_mime_type; - std::string uncompressed_audio_mime_type; - std::string compressed_video_mime_type; - std::string uncompressed_video_mime_type; - base::TimeDelta frame_duration; - base::TimeDelta media_duration; - int64 media_total_bytes; -}; - - -class MockDataSource : public DataSource { - public: - explicit MockDataSource(const MockFilterConfig* config) - : config_(config), - position_(0), - deleted_(NULL) { - } - - MockDataSource(const MockFilterConfig* config, bool* deleted) - : config_(config), - position_(0), - deleted_(deleted) { - EXPECT_TRUE(deleted); - EXPECT_FALSE(*deleted); - } - - // Implementation of MediaFilter. - virtual void Stop() {} - - virtual void Seek(base::TimeDelta time) { - seek_time_ = time; - } - - // Implementation of DataSource. - virtual bool Initialize(const std::string& url) { - media_format_.SetAsString(MediaFormat::kMimeType, - mime_type::kApplicationOctetStream); - media_format_.SetAsString(MediaFormat::kURL, url); - host()->SetTotalBytes(config_->media_total_bytes); - switch (config_->data_source_behavior) { - case MOCK_DATA_SOURCE_NORMAL_INIT: - host()->InitializationComplete(); - return true; - case MOCK_DATA_SOURCE_NEVER_INIT: - return true; - case MOCK_DATA_SOURCE_URL_ERROR_IN_INIT: - host()->Error(PIPELINE_ERROR_URL_NOT_FOUND); - return false; - case MOCK_DATA_SOURCE_INIT_RETURN_FALSE: - return false; - default: - NOTREACHED(); - return false; - } - } - - virtual const MediaFormat& media_format() { - return media_format_; - } - - virtual size_t Read(uint8* data, size_t size) { - size_t read = static_cast<size_t>(config_->media_total_bytes - position_); - if (size < read) { - read = size; - } - memset(data, config_->data_source_value, read); - return read; - } - - virtual bool GetPosition(int64* position_out) { - *position_out = position_; - return true; - } - - virtual bool SetPosition(int64 position) { - if (position < 0u || position > config_->media_total_bytes) { - return false; - } - position_ = position; - return true; - } - - virtual bool GetSize(int64* size_out) { - if (config_->media_total_bytes >= 0) { - *size_out = config_->media_total_bytes; - return true; - } - return false; - } - - virtual bool IsSeekable() { - return true; - } - - // Mock accessors. - int64 position() const { return position_; } - const base::TimeDelta& seek_time() const { return seek_time_; } - - private: - virtual ~MockDataSource() { - if (deleted_) { - *deleted_ = true; - } - } - - const MockFilterConfig* config_; - int64 position_; - MediaFormat media_format_; - base::TimeDelta seek_time_; - - // Set to true inside the destructor. Used in FFmpegGlue unit tests for - // testing proper reference counting. - bool* deleted_; - - DISALLOW_COPY_AND_ASSIGN(MockDataSource); -}; - - -class MockDemuxerStream : public DemuxerStream { - public: - MockDemuxerStream(const MockFilterConfig* config, bool is_audio) { - if (is_audio) { - media_format_.SetAsString(MediaFormat::kMimeType, - config->compressed_audio_mime_type); - } else { - media_format_.SetAsString(MediaFormat::kMimeType, - config->compressed_video_mime_type); - media_format_.SetAsInteger(MediaFormat::kWidth, config->video_width); - media_format_.SetAsInteger(MediaFormat::kHeight, config->video_height); - } - } - - // Implementation of DemuxerStream. - virtual const MediaFormat& media_format() { - return media_format_; - } - - virtual void Read(Callback1<Buffer*>::Type* read_callback) { - NOTREACHED(); // TODO(ralphl): fix me!! - } - - private: - virtual ~MockDemuxerStream() {} - - MediaFormat media_format_; - - DISALLOW_COPY_AND_ASSIGN(MockDemuxerStream); -}; - - -class MockDemuxer : public Demuxer { - public: - explicit MockDemuxer(const MockFilterConfig* config) - : config_(config), - mock_audio_stream_(new MockDemuxerStream(config, true)), - mock_video_stream_(new MockDemuxerStream(config, false)) { - } - - // Implementation of MediaFilter. - virtual void Stop() {} - - virtual void Seek(base::TimeDelta time) { - seek_time_ = time; - } - - // Implementation of Demuxer. - virtual bool Initialize(DataSource* data_source) { - host()->InitializationComplete(); - return true; - } - - virtual size_t GetNumberOfStreams() { - size_t num_streams = 0; - if (config_->has_audio) { - ++num_streams; - } - if (config_->has_video) { - ++num_streams; - } - return num_streams; - } - - virtual scoped_refptr<DemuxerStream> GetStream(int stream_id) { - switch (stream_id) { - case 0: - if (config_->has_audio) { - return mock_audio_stream_; - } else if (config_->has_video) { - return mock_video_stream_; - } - break; - case 1: - if (config_->has_audio && config_->has_video) { - return mock_video_stream_; - } - break; - } - ADD_FAILURE(); - return NULL; - } - - // Mock accessors. - const base::TimeDelta& seek_time() const { return seek_time_; } - - private: - virtual ~MockDemuxer() {} - - const MockFilterConfig* config_; - scoped_refptr<DemuxerStream> mock_audio_stream_; - scoped_refptr<DemuxerStream> mock_video_stream_; - base::TimeDelta seek_time_; - - DISALLOW_COPY_AND_ASSIGN(MockDemuxer); -}; - - -class MockAudioDecoder : public AudioDecoder { - public: - explicit MockAudioDecoder(const MockFilterConfig* config) { - media_format_.SetAsString(MediaFormat::kMimeType, - config->uncompressed_audio_mime_type); - } - - // Implementation of MediaFilter. - virtual void Stop() {} - - virtual void Seek(base::TimeDelta time) { - seek_time_ = time; - } - - // Implementation of AudioDecoder. - virtual bool Initialize(DemuxerStream* stream) { - host()->InitializationComplete(); - return true; - } - - virtual const MediaFormat& media_format() { - return media_format_; - } - - virtual void Read(Callback1<Buffer*>::Type* callback) { - // TODO(ralphl): implement mock read. - NOTREACHED(); - } - - // Mock accessors. - const base::TimeDelta& seek_time() const { return seek_time_; } - - private: - virtual ~MockAudioDecoder() {} - - MediaFormat media_format_; - base::TimeDelta seek_time_; - - DISALLOW_COPY_AND_ASSIGN(MockAudioDecoder); -}; - - -class MockAudioRenderer : public AudioRenderer { - public: - explicit MockAudioRenderer(const MockFilterConfig* config) {} - - // Implementation of MediaFilter. - virtual void Stop() {} - - virtual void Seek(base::TimeDelta time) { - seek_time_ = time; - } - - // Implementation of AudioRenderer. - virtual bool Initialize(AudioDecoder* decoder) { - host()->InitializationComplete(); - return true; - } - - virtual void SetVolume(float volume) {} - - // Mock accessors. - const base::TimeDelta& seek_time() const { return seek_time_; } - - private: - virtual ~MockAudioRenderer() {} - - base::TimeDelta seek_time_; - - DISALLOW_COPY_AND_ASSIGN(MockAudioRenderer); -}; - - -class MockVideoDecoder : public VideoDecoder { - public: - // Helper function that initializes a YV12 frame with white and black scan - // lines based on the |white_to_black| parameter. If 0, then the entire - // frame will be black, if 1 then the entire frame will be white. - static void InitializeYV12Frame(VideoFrame* frame, double white_to_black) { - VideoSurface surface; - if (!frame->Lock(&surface)) { - ADD_FAILURE(); - } else { - EXPECT_EQ(surface.format, VideoSurface::YV12); - size_t first_black_row = static_cast<size_t>(surface.height * - white_to_black); - uint8* y_plane = surface.data[VideoSurface::kYPlane]; - for (size_t row = 0; row < surface.height; ++row) { - int color = (row < first_black_row) ? 0xFF : 0x00; - memset(y_plane, color, surface.width); - y_plane += surface.strides[VideoSurface::kYPlane]; - } - uint8* u_plane = surface.data[VideoSurface::kUPlane]; - uint8* v_plane = surface.data[VideoSurface::kVPlane]; - for (size_t row = 0; row < surface.height; row += 2) { - memset(u_plane, 0x80, surface.width / 2); - memset(v_plane, 0x80, surface.width / 2); - u_plane += surface.strides[VideoSurface::kUPlane]; - v_plane += surface.strides[VideoSurface::kVPlane]; - } - frame->Unlock(); - } - } - - explicit MockVideoDecoder(const MockFilterConfig* config) - : config_(config) { - media_format_.SetAsString(MediaFormat::kMimeType, - config->uncompressed_video_mime_type); - media_format_.SetAsInteger(MediaFormat::kWidth, config->video_width); - media_format_.SetAsInteger(MediaFormat::kHeight, config->video_height); - } - - // Implementation of MediaFilter. - virtual void Stop() {} - - virtual void Seek(base::TimeDelta time) { - seek_time_ = time; - } - - // Implementation of VideoDecoder. - virtual bool Initialize(DemuxerStream* stream) { - host()->InitializationComplete(); - return true; - } - - virtual const MediaFormat& media_format() { - return media_format_; - } - - virtual void Read(Callback1<VideoFrame*>::Type* callback) { - DoRead(callback); - } - - // Mock accessors. - const base::TimeDelta& seek_time() const { return seek_time_; } - - private: - virtual ~MockVideoDecoder() {} - - void DoRead(Callback1<VideoFrame*>::Type* callback) { - scoped_ptr<Callback1<VideoFrame*>::Type> scoped_callback(callback); - if (mock_frame_time_ < config_->media_duration) { - // TODO(ralphl): Mock video decoder only works with YV12. Implement other - // formats as needed. - EXPECT_EQ(config_->video_surface_format, VideoSurface::YV12); - scoped_refptr<VideoFrame> frame; - VideoFrameImpl::CreateFrame(config_->video_surface_format, - config_->video_width, - config_->video_height, - mock_frame_time_, - config_->frame_duration, - &frame); - if (!frame) { - host()->Error(PIPELINE_ERROR_OUT_OF_MEMORY); - ADD_FAILURE(); - } else { - mock_frame_time_ += config_->frame_duration; - if (mock_frame_time_ >= config_->media_duration) { - VideoFrameImpl::CreateEmptyFrame(&frame); - } else { - InitializeYV12Frame(frame, (mock_frame_time_.InSecondsF() / - config_->media_duration.InSecondsF())); - } - callback->Run(frame); - } - } - } - - MediaFormat media_format_; - base::TimeDelta mock_frame_time_; - base::TimeDelta seek_time_; - const MockFilterConfig* config_; - - DISALLOW_COPY_AND_ASSIGN(MockVideoDecoder); -}; - - -class MockVideoRenderer : public VideoRenderer { - public: - explicit MockVideoRenderer(const MockFilterConfig* config) - : config_(config) { - } - - // Implementation of MediaFilter. - virtual void Stop() {} - - virtual void Seek(base::TimeDelta time) { - seek_time_ = time; - } - - // Implementation of VideoRenderer. - virtual bool Initialize(VideoDecoder* decoder) { - host()->SetVideoSize(config_->video_width, config_->video_height); - host()->InitializationComplete(); - return true; - } - - // Mock accessors. - const base::TimeDelta& seek_time() const { return seek_time_; } - - private: - virtual ~MockVideoRenderer() {} - - base::TimeDelta seek_time_; - const MockFilterConfig* config_; - - DISALLOW_COPY_AND_ASSIGN(MockVideoRenderer); -}; - - -// FilterFactory capable of creating each mock filter type. Only one instance -// of each filter type can exist at any time. Filters can be inspected for -// expectations using the accessors, which may return NULL if the filter was -// never created (i.e., streams containing no video). -class MockFilterFactory : public FilterFactory { - public: - explicit MockFilterFactory(const MockFilterConfig* config) - : config_(config) { - } - - // Mock accessors. - MockDataSource* data_source() const { return data_source_; } - MockDemuxer* demuxer() const { return demuxer_; } - MockAudioDecoder* audio_decoder() const { return audio_decoder_; } - MockVideoDecoder* video_decoder() const { return video_decoder_; } - MockAudioRenderer* audio_renderer() const { return audio_renderer_; } - MockVideoRenderer* video_renderer() const { return video_renderer_; } - - protected: - MediaFilter* Create(FilterType filter_type, const MediaFormat& media_format) { - if (!config_->create_filter) - return NULL; - - switch (filter_type) { - case FILTER_DATA_SOURCE: - DCHECK(!data_source_); - data_source_ = new MockDataSource(config_); - return data_source_; - - case FILTER_DEMUXER: - DCHECK(!demuxer_); - demuxer_ = new MockDemuxer(config_); - return demuxer_; - - case FILTER_AUDIO_DECODER: - DCHECK(!audio_decoder_); - audio_decoder_ = new MockAudioDecoder(config_); - return audio_decoder_; - - case FILTER_VIDEO_DECODER: - DCHECK(!video_decoder_); - video_decoder_ = new MockVideoDecoder(config_); - return video_decoder_; - - case FILTER_AUDIO_RENDERER: - DCHECK(!audio_renderer_); - audio_renderer_ = new MockAudioRenderer(config_); - return audio_renderer_; - - case FILTER_VIDEO_RENDERER: - DCHECK(!video_renderer_); - video_renderer_ = new MockVideoRenderer(config_); - return video_renderer_; - - default: - NOTREACHED(); - } - return NULL; - } - - private: - const MockFilterConfig* config_; - scoped_refptr<MockDataSource> data_source_; - scoped_refptr<MockDemuxer> demuxer_; - scoped_refptr<MockAudioDecoder> audio_decoder_; - scoped_refptr<MockVideoDecoder> video_decoder_; - scoped_refptr<MockAudioRenderer> audio_renderer_; - scoped_refptr<MockVideoRenderer> video_renderer_; - - DISALLOW_COPY_AND_ASSIGN(MockFilterFactory); -}; - -// A simple class that waits for a pipeline to be started and checks some -// basic initialization values. The Start() method will not return until -// either a pre-determined amount of time has passed or the pipeline calls the -// InitCallback() callback. A typical use would be: -// Pipeline p; -// FilterFactoryCollection f; -// f->AddFactory(a); -// f->AddFactory(b); -// ... -// InitializationHelper h; -// h.Start(&p, f, uri); -// -// If the test is expecting to produce an error use would be: -// h.Start(&p, f, uri, PIPELINE_ERROR_REQUIRED_FILTER_MISSING) -// -// If the test expects the pipeline to hang during initialization (a filter -// never calls FilterHost::InitializationComplete()) then the use would be: -// h.Start(&p, f, uri, PIPELINE_OK, true); -// -// TODO(scherkus): Keep refactoring tests until we can remove this entirely. -class InitializationHelper { - public: - InitializationHelper() - : event_(true, false), - callback_success_status_(false), - waiting_for_callback_(false) {} - - // If callback has been called, then returns the boolean passed by the - // pipeline to the callback. - bool callback_success_status() { return callback_success_status_; } - - // Returns true if Start has been called, but the pipeline has not yet - // called the initialization complete callback. - bool waiting_for_callback() { return waiting_for_callback_; } - - // Starts the pipeline, providing an initialization callback that points - // to this object. - void Start(Pipeline* pipeline, - FilterFactory* filter_factory, - const std::string& uri, - PipelineError expect_error = PIPELINE_OK, - bool expect_hang = false) { - // For tests that we expect to hang in initialization, we want to - // wait a short time. If a hang is not expected, then wait long enough - // to make sure that the filters have time to initalize. 1/2 second if - // we expect to hang, and 3 seconds if we expect success. - base::TimeDelta max_wait = base::TimeDelta::FromMilliseconds(expect_hang ? - 500 : 3000); - EXPECT_FALSE(waiting_for_callback_); - waiting_for_callback_ = true; - callback_success_status_ = false; - event_.Reset(); - pipeline->Start(filter_factory, uri, - NewCallback(this, &InitializationHelper::InitCallback)); - bool signaled = event_.TimedWait(max_wait); - if (expect_hang) { - EXPECT_FALSE(signaled); - EXPECT_FALSE(pipeline->IsInitialized()); - EXPECT_TRUE(waiting_for_callback_); - } else { - EXPECT_TRUE(signaled); - EXPECT_FALSE(waiting_for_callback_); - EXPECT_EQ(pipeline->GetError(), expect_error); - EXPECT_EQ(callback_success_status_, (expect_error == PIPELINE_OK)); - EXPECT_EQ(pipeline->IsInitialized(), (expect_error == PIPELINE_OK)); - } - } - - private: - void InitCallback(bool success) { - EXPECT_TRUE(waiting_for_callback_); - EXPECT_FALSE(event_.IsSignaled()); - waiting_for_callback_ = false; - callback_success_status_ = success; - event_.Signal(); - } - - base::WaitableEvent event_; - bool callback_success_status_; - bool waiting_for_callback_; - - DISALLOW_COPY_AND_ASSIGN(InitializationHelper); -}; - -} // namespace old_mocks - -} // namespace media - -#endif // MEDIA_BASE_MOCK_MEDIA_FILTERS_H_ diff --git a/media/base/pipeline_impl_unittest.cc b/media/base/pipeline_impl_unittest.cc index 56aa246..4183126 100644 --- a/media/base/pipeline_impl_unittest.cc +++ b/media/base/pipeline_impl_unittest.cc @@ -10,34 +10,38 @@ #include "media/base/filters.h" #include "media/base/factory.h" #include "media/base/filter_host.h" -#include "media/base/mock_media_filters.h" +#include "media/base/mock_filters.h" #include "testing/gtest/include/gtest/gtest.h" -namespace { +using ::testing::DoAll; +using ::testing::Return; +using ::testing::StrictMock; -class PipelineImplTest : public testing::Test { - protected: +namespace media { + +typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector; + +class PipelineImplTest : public ::testing::Test { + public: PipelineImplTest() - : initialize_result_(false), + : mocks_(new MockFilterFactory()), + initialize_result_(false), seek_result_(false), initialize_event_(false, false), seek_event_(false, false) { } - virtual ~PipelineImplTest() {} - - virtual void TearDown() { + virtual ~PipelineImplTest() { // Force the pipeline to shut down its thread. pipeline_.Stop(); } + protected: // Called by tests after they have finished setting up MockFilterConfig. // Initializes the pipeline and returns true if the initialization callback // was executed, false otherwise. bool InitializeAndWait() { - DCHECK(!filters_); - filters_ = new media::old_mocks::MockFilterFactory(&config_); - pipeline_.Start(filters_, "", + pipeline_.Start(mocks_, "", NewCallback(this, &PipelineImplTest::OnInitialize)); return initialize_event_.TimedWait(base::TimeDelta::FromMilliseconds(500)); } @@ -49,10 +53,66 @@ class PipelineImplTest : public testing::Test { return seek_event_.TimedWait(base::TimeDelta::FromMilliseconds(500)); } + // Sets up expectations to allow the data source to initialize. + void InitializeDataSource() { + EXPECT_CALL(*mocks_->data_source(), Initialize("")) + .WillOnce(DoAll(InitializationComplete(mocks_->data_source()), + Return(true))); + EXPECT_CALL(*mocks_->data_source(), Stop()); + } + + // Sets up expectations to allow the demuxer to initialize. + void InitializeDemuxer(MockDemuxerStreamVector* streams) { + EXPECT_CALL(*mocks_->demuxer(), Initialize(mocks_->data_source())) + .WillOnce(DoAll(InitializationComplete(mocks_->demuxer()), + Return(true))); + EXPECT_CALL(*mocks_->demuxer(), GetNumberOfStreams()) + .WillRepeatedly(Return(streams->size())); + EXPECT_CALL(*mocks_->demuxer(), Stop()); + + // Configure the demuxer to return the streams. + for (size_t i = 0; i < streams->size(); ++i) { + scoped_refptr<DemuxerStream> stream = (*streams)[i]; + EXPECT_CALL(*mocks_->demuxer(), GetStream(i)) + .WillRepeatedly(Return(stream)); + } + } + + // Sets up expectations to allow the video decoder to initialize. + void InitializeVideoDecoder(MockDemuxerStream* stream) { + EXPECT_CALL(*mocks_->video_decoder(), Initialize(stream)) + .WillOnce(DoAll(InitializationComplete(mocks_->video_decoder()), + Return(true))); + EXPECT_CALL(*mocks_->video_decoder(), Stop()); + } + + // Sets up expectations to allow the audio decoder to initialize. + void InitializeAudioDecoder(MockDemuxerStream* stream) { + EXPECT_CALL(*mocks_->audio_decoder(), Initialize(stream)) + .WillOnce(DoAll(InitializationComplete(mocks_->audio_decoder()), + Return(true))); + EXPECT_CALL(*mocks_->audio_decoder(), Stop()); + } + + // Sets up expectations to allow the video renderer to initialize. + void InitializeVideoRenderer() { + EXPECT_CALL(*mocks_->video_renderer(), Initialize(mocks_->video_decoder())) + .WillOnce(DoAll(InitializationComplete(mocks_->video_renderer()), + Return(true))); + EXPECT_CALL(*mocks_->video_renderer(), Stop()); + } + + // Sets up expectations to allow the audio renderer to initialize. + void InitializeAudioRenderer() { + EXPECT_CALL(*mocks_->audio_renderer(), Initialize(mocks_->audio_decoder())) + .WillOnce(DoAll(InitializationComplete(mocks_->audio_renderer()), + Return(true))); + EXPECT_CALL(*mocks_->audio_renderer(), Stop()); + } + // Fixture members. media::PipelineImpl pipeline_; - scoped_refptr<media::old_mocks::MockFilterFactory> filters_; - media::old_mocks::MockFilterConfig config_; + scoped_refptr<media::MockFilterFactory> mocks_; bool initialize_result_; bool seek_result_; @@ -75,7 +135,9 @@ class PipelineImplTest : public testing::Test { }; TEST_F(PipelineImplTest, NeverInitializes) { - config_.data_source_behavior = media::old_mocks::MOCK_DATA_SOURCE_NEVER_INIT; + EXPECT_CALL(*mocks_->data_source(), Initialize("")) + .WillOnce(Return(true)); + EXPECT_CALL(*mocks_->data_source(), Stop()); // This test hangs during initialization by never calling // InitializationComplete(). Make sure we tear down the pipeline properly. @@ -86,7 +148,7 @@ TEST_F(PipelineImplTest, NeverInitializes) { } TEST_F(PipelineImplTest, RequiredFilterMissing) { - config_.create_filter = false; + mocks_->set_creation_successful(false); ASSERT_TRUE(InitializeAndWait()); EXPECT_FALSE(initialize_result_); @@ -96,8 +158,11 @@ TEST_F(PipelineImplTest, RequiredFilterMissing) { } TEST_F(PipelineImplTest, URLNotFound) { - config_.data_source_behavior = - media::old_mocks::MOCK_DATA_SOURCE_URL_ERROR_IN_INIT; + EXPECT_CALL(*mocks_->data_source(), Initialize("")) + .WillOnce(DoAll(Error(mocks_->data_source(), + PIPELINE_ERROR_URL_NOT_FOUND), + Return(false))); + EXPECT_CALL(*mocks_->data_source(), Stop()); ASSERT_TRUE(InitializeAndWait()); EXPECT_FALSE(initialize_result_); @@ -106,117 +171,128 @@ TEST_F(PipelineImplTest, URLNotFound) { } TEST_F(PipelineImplTest, NoStreams) { - config_.has_audio = false; - config_.has_video = false; + MockDemuxerStreamVector streams; + InitializeDataSource(); + InitializeDemuxer(&streams); ASSERT_TRUE(InitializeAndWait()); EXPECT_FALSE(initialize_result_); EXPECT_FALSE(pipeline_.IsInitialized()); EXPECT_EQ(media::PIPELINE_ERROR_COULD_NOT_RENDER, pipeline_.GetError()); - - EXPECT_FALSE(filters_->audio_decoder()); - EXPECT_FALSE(filters_->audio_renderer()); - EXPECT_FALSE(filters_->video_decoder()); - EXPECT_FALSE(filters_->video_renderer()); } TEST_F(PipelineImplTest, AudioStream) { - config_.has_video = false; + scoped_refptr<StrictMock<MockDemuxerStream> > stream = + new StrictMock<MockDemuxerStream>("audio/x-foo"); + MockDemuxerStreamVector streams; + streams.push_back(stream); + + InitializeDataSource(); + InitializeDemuxer(&streams); + InitializeAudioDecoder(stream); + InitializeAudioRenderer(); ASSERT_TRUE(InitializeAndWait()); EXPECT_TRUE(initialize_result_); EXPECT_TRUE(pipeline_.IsInitialized()); EXPECT_EQ(media::PIPELINE_OK, pipeline_.GetError()); - - size_t width, height; - pipeline_.GetVideoSize(&width, &height); - EXPECT_EQ(0u, width); - EXPECT_EQ(0u, height); EXPECT_TRUE(pipeline_.IsRendered(media::mime_type::kMajorTypeAudio)); EXPECT_FALSE(pipeline_.IsRendered(media::mime_type::kMajorTypeVideo)); - - EXPECT_TRUE(filters_->audio_decoder()); - EXPECT_TRUE(filters_->audio_renderer()); - EXPECT_FALSE(filters_->video_decoder()); - EXPECT_FALSE(filters_->video_renderer()); } TEST_F(PipelineImplTest, VideoStream) { - config_.has_audio = false; + scoped_refptr<StrictMock<MockDemuxerStream> > stream = + new StrictMock<MockDemuxerStream>("video/x-foo"); + MockDemuxerStreamVector streams; + streams.push_back(stream); + + InitializeDataSource(); + InitializeDemuxer(&streams); + InitializeVideoDecoder(stream); + InitializeVideoRenderer(); ASSERT_TRUE(InitializeAndWait()); EXPECT_TRUE(initialize_result_); EXPECT_TRUE(pipeline_.IsInitialized()); EXPECT_EQ(media::PIPELINE_OK, pipeline_.GetError()); - - size_t width, height; - pipeline_.GetVideoSize(&width, &height); - EXPECT_EQ(config_.video_width, width); - EXPECT_EQ(config_.video_height, height); EXPECT_FALSE(pipeline_.IsRendered(media::mime_type::kMajorTypeAudio)); EXPECT_TRUE(pipeline_.IsRendered(media::mime_type::kMajorTypeVideo)); - - EXPECT_FALSE(filters_->audio_decoder()); - EXPECT_FALSE(filters_->audio_renderer()); - EXPECT_TRUE(filters_->video_decoder()); - EXPECT_TRUE(filters_->video_renderer()); } TEST_F(PipelineImplTest, AudioVideoStream) { + scoped_refptr<StrictMock<MockDemuxerStream> > audio_stream = + new StrictMock<MockDemuxerStream>("audio/x-foo"); + scoped_refptr<StrictMock<MockDemuxerStream> > video_stream = + new StrictMock<MockDemuxerStream>("video/x-foo"); + MockDemuxerStreamVector streams; + streams.push_back(audio_stream); + streams.push_back(video_stream); + + InitializeDataSource(); + InitializeDemuxer(&streams); + InitializeAudioDecoder(audio_stream); + InitializeAudioRenderer(); + InitializeVideoDecoder(video_stream); + InitializeVideoRenderer(); + ASSERT_TRUE(InitializeAndWait()); EXPECT_TRUE(initialize_result_); EXPECT_TRUE(pipeline_.IsInitialized()); EXPECT_EQ(media::PIPELINE_OK, pipeline_.GetError()); - - size_t width, height; - pipeline_.GetVideoSize(&width, &height); - EXPECT_EQ(config_.video_width, width); - EXPECT_EQ(config_.video_height, height); EXPECT_TRUE(pipeline_.IsRendered(media::mime_type::kMajorTypeAudio)); EXPECT_TRUE(pipeline_.IsRendered(media::mime_type::kMajorTypeVideo)); - - EXPECT_TRUE(filters_->audio_decoder()); - EXPECT_TRUE(filters_->audio_renderer()); - EXPECT_TRUE(filters_->video_decoder()); - EXPECT_TRUE(filters_->video_renderer()); } TEST_F(PipelineImplTest, Seek) { - ASSERT_TRUE(InitializeAndWait()); - - // Seek and verify callback returned true. + scoped_refptr<StrictMock<MockDemuxerStream> > audio_stream = + new StrictMock<MockDemuxerStream>("audio/x-foo"); + scoped_refptr<StrictMock<MockDemuxerStream> > video_stream = + new StrictMock<MockDemuxerStream>("video/x-foo"); + MockDemuxerStreamVector streams; + streams.push_back(audio_stream); + streams.push_back(video_stream); + + InitializeDataSource(); + InitializeDemuxer(&streams); + InitializeAudioDecoder(audio_stream); + InitializeAudioRenderer(); + InitializeVideoDecoder(video_stream); + InitializeVideoRenderer(); + + // Every filter should receive a call to Seek(). base::TimeDelta expected = base::TimeDelta::FromSeconds(2000); + EXPECT_CALL(*mocks_->data_source(), Seek(expected)); + EXPECT_CALL(*mocks_->demuxer(), Seek(expected)); + EXPECT_CALL(*mocks_->audio_decoder(), Seek(expected)); + EXPECT_CALL(*mocks_->audio_renderer(), Seek(expected)); + EXPECT_CALL(*mocks_->video_decoder(), Seek(expected)); + EXPECT_CALL(*mocks_->video_renderer(), Seek(expected)); + + // Initialize then seek! + ASSERT_TRUE(InitializeAndWait()); EXPECT_TRUE(SeekAndWait(expected)); EXPECT_TRUE(seek_result_); - - // Verify every filter received the seek. - // TODO(scherkus): implement whatever it takes so I can use EXPECT_EQ with - // base::TimeDelta. - EXPECT_TRUE(expected == filters_->data_source()->seek_time()); - EXPECT_TRUE(expected == filters_->demuxer()->seek_time()); - EXPECT_TRUE(expected == filters_->audio_decoder()->seek_time()); - EXPECT_TRUE(expected == filters_->audio_renderer()->seek_time()); - EXPECT_TRUE(expected == filters_->video_decoder()->seek_time()); - EXPECT_TRUE(expected == filters_->video_renderer()->seek_time()); } -// Try to execute Start()/Stop() on the Pipeline many times and very fast. This -// test is trying to simulate the situation where the pipeline can get dead -// locked very easily by quickly calling Start()/Stop(). -TEST_F(PipelineImplTest, StressTestPipelineStartStop) { - media::old_mocks::MockFilterConfig config; - const int kTimes = 1000; - for (int i = 0; i < kTimes; ++i) { - scoped_refptr<media::old_mocks::MockFilterFactory> factory = - new media::old_mocks::MockFilterFactory(&config); - media::PipelineImpl pipeline; - pipeline.Start(factory.get(), "", NULL); - pipeline.Stop(); - } +TEST_F(PipelineImplTest, SetVolume) { + scoped_refptr<StrictMock<MockDemuxerStream> > audio_stream = + new StrictMock<MockDemuxerStream>("audio/x-foo"); + MockDemuxerStreamVector streams; + streams.push_back(audio_stream); + + InitializeDataSource(); + InitializeDemuxer(&streams); + InitializeAudioDecoder(audio_stream); + InitializeAudioRenderer(); + + // The audio renderer should receive a call to SetVolume(). + float expected = 0.5f; + EXPECT_CALL(*mocks_->audio_renderer(), SetVolume(expected)); + + // Initialize then set volume! + ASSERT_TRUE(InitializeAndWait()); + pipeline_.SetVolume(expected); } -// TODO(ralphl): Add a unit test that makes sure that the mock audio filter -// is actually called on a SetVolume() call to the pipeline. I almost checked -// in code that broke this, but all unit tests were passing. +} // namespace media -} // namespace diff --git a/media/base/video_frame_impl_unittest.cc b/media/base/video_frame_impl_unittest.cc index a6a1a6a..eeec716 100644 --- a/media/base/video_frame_impl_unittest.cc +++ b/media/base/video_frame_impl_unittest.cc @@ -3,15 +3,40 @@ // found in the LICENSE file. #include "media/base/buffers.h" -#include "media/base/mock_media_filters.h" +#include "media/base/mock_filters.h" #include "media/base/video_frame_impl.h" #include "media/base/yuv_convert.h" #include "testing/gtest/include/gtest/gtest.h" -using media::VideoFrameImpl; -using media::VideoSurface; +namespace media { -namespace { +// Helper function that initializes a YV12 frame with white and black scan +// lines based on the |white_to_black| parameter. If 0, then the entire +// frame will be black, if 1 then the entire frame will be white. +void InitializeYV12Frame(VideoFrame* frame, double white_to_black) { + VideoSurface surface; + if (!frame->Lock(&surface)) { + ADD_FAILURE(); + return; + } + EXPECT_EQ(surface.format, VideoSurface::YV12); + size_t first_black_row = static_cast<size_t>(surface.height * white_to_black); + uint8* y_plane = surface.data[VideoSurface::kYPlane]; + for (size_t row = 0; row < surface.height; ++row) { + int color = (row < first_black_row) ? 0xFF : 0x00; + memset(y_plane, color, surface.width); + y_plane += surface.strides[VideoSurface::kYPlane]; + } + uint8* u_plane = surface.data[VideoSurface::kUPlane]; + uint8* v_plane = surface.data[VideoSurface::kVPlane]; + for (size_t row = 0; row < surface.height; row += 2) { + memset(u_plane, 0x80, surface.width / 2); + memset(v_plane, 0x80, surface.width / 2); + u_plane += surface.strides[VideoSurface::kUPlane]; + v_plane += surface.strides[VideoSurface::kVPlane]; + } + frame->Unlock(); +} // Given a |yv12_frame| this method converts the YV12 frame to RGBA and // makes sure that all the pixels of the RBG frame equal |expect_rgb_color|. @@ -65,10 +90,7 @@ void ExpectFrameColor(media::VideoFrame* yv12_frame, uint32 expect_rgb_color) { yv12_frame->Unlock(); } -} // namespace - - -TEST(VideoFrameImpl, Basic) { +TEST(VideoFrameImpl, CreateFrame) { const size_t kWidth = 64; const size_t kHeight = 48; const base::TimeDelta kTimestampA = base::TimeDelta::FromMicroseconds(1337); @@ -78,8 +100,8 @@ TEST(VideoFrameImpl, Basic) { // Create a YV12 Video Frame. scoped_refptr<media::VideoFrame> frame; - media::VideoFrameImpl::CreateFrame(media::VideoSurface::YV12, kWidth, kHeight, - kTimestampA, kDurationA, &frame); + VideoFrameImpl::CreateFrame(media::VideoSurface::YV12, kWidth, kHeight, + kTimestampA, kDurationA, &frame); ASSERT_TRUE(frame); // Test StreamSample implementation. @@ -98,12 +120,14 @@ TEST(VideoFrameImpl, Basic) { EXPECT_FALSE(frame->IsDiscontinuous()); // Test VideoFrame implementation. - media::old_mocks::MockVideoDecoder::InitializeYV12Frame(frame, 0.0f); + InitializeYV12Frame(frame, 0.0f); ExpectFrameColor(frame, 0xFF000000); - media::old_mocks::MockVideoDecoder::InitializeYV12Frame(frame, 1.0f); + InitializeYV12Frame(frame, 1.0f); ExpectFrameColor(frame, 0xFFFFFFFF); // Test an empty frame. - media::VideoFrameImpl::CreateEmptyFrame(&frame); + VideoFrameImpl::CreateEmptyFrame(&frame); EXPECT_TRUE(frame->IsEndOfStream()); } + +} // namespace media |