| Index: media/audio/audio_debug_recording_helper_unittest.cc
|
| diff --git a/media/audio/audio_debug_recording_helper_unittest.cc b/media/audio/audio_debug_recording_helper_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..14af533a43cdea2659a6c5f683582786b5c35925
|
| --- /dev/null
|
| +++ b/media/audio/audio_debug_recording_helper_unittest.cc
|
| @@ -0,0 +1,233 @@
|
| +// Copyright 2017 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/audio/audio_debug_recording_helper.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/files/file_path.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "base/test/test_message_loop.h"
|
| +#include "media/base/audio_bus.h"
|
| +#include "media/base/audio_sample_types.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using testing::_;
|
| +using testing::Return;
|
| +
|
| +#if defined(OS_WIN)
|
| +#define IntToStringType base::IntToString16
|
| +#else
|
| +#define IntToStringType base::IntToString
|
| +#endif
|
| +
|
| +namespace media {
|
| +
|
| +namespace {
|
| +
|
| +// The filename extension the mock should return in GetFileNameExtension().
|
| +const base::FilePath::CharType kFileNameExtension[] = FILE_PATH_LITERAL("wav");
|
| +
|
| +} // namespace
|
| +
|
| +// Mock class for the audio file writer that the helper wraps.
|
| +class MockAudioFileWriter : public AudioFileWriter {
|
| + public:
|
| + MockAudioFileWriter(const AudioParameters& params)
|
| + : params_(params), reference_data_(nullptr) {}
|
| + ~MockAudioFileWriter() override {}
|
| +
|
| + MOCK_METHOD1(Start, void(const base::FilePath&));
|
| + MOCK_METHOD0(Stop, void());
|
| +
|
| + // Functions with move-only types as arguments can't be mocked directly, so
|
| + // we pass on to DoWrite(). Also, we can verify the data this way.
|
| + MOCK_METHOD1(DoWrite, void(AudioBus*));
|
| + void Write(std::unique_ptr<AudioBus> data) override {
|
| + CHECK(reference_data_);
|
| + EXPECT_EQ(reference_data_->channels(), data->channels());
|
| + EXPECT_EQ(reference_data_->frames(), data->frames());
|
| + for (int i = 0; i < data->channels(); ++i) {
|
| + float* data_ptr = data->channel(i);
|
| + float* ref_data_ptr = reference_data_->channel(i);
|
| + for (int j = 0; j < data->frames(); ++j, ++data_ptr, ++ref_data_ptr)
|
| + EXPECT_EQ(*ref_data_ptr, *data_ptr);
|
| + }
|
| + DoWrite(data.get());
|
| + }
|
| +
|
| + MOCK_METHOD0(WillWrite, bool());
|
| + MOCK_METHOD0(GetFileNameExtension, const base::FilePath::CharType*());
|
| +
|
| + // Set reference data to compare against. Must be called before Write() is
|
| + // called.
|
| + void SetReferenceData(AudioBus* reference_data) {
|
| + EXPECT_EQ(params_.channels(), reference_data->channels());
|
| + EXPECT_EQ(params_.frames_per_buffer(), reference_data->frames());
|
| + reference_data_ = reference_data;
|
| + }
|
| +
|
| + private:
|
| + const AudioParameters params_;
|
| + AudioBus* reference_data_;
|
| +};
|
| +
|
| +// The test fixture.
|
| +class AudioDebugRecordingHelperTest : public ::testing::Test {
|
| + public:
|
| + AudioDebugRecordingHelperTest()
|
| + : file_path_(base::FilePath::FromUTF8Unsafe("file_path")),
|
| + mock_audio_file_writer_(nullptr) {}
|
| +
|
| + ~AudioDebugRecordingHelperTest() override {}
|
| +
|
| + // Creates the mock writer, passed as a callback to the helper and called by
|
| + // the helper. After the mock writer is returned, we always expect
|
| + // GetFileNameExtension() and Start() to be called on it by the helper.
|
| + std::unique_ptr<AudioFileWriter> CreateMockAudioFileWriter(
|
| + const AudioParameters& params) {
|
| + CHECK(!mock_audio_file_writer_);
|
| + MockAudioFileWriter* writer = new MockAudioFileWriter(params);
|
| + EXPECT_CALL(*writer, GetFileNameExtension())
|
| + .WillOnce(Return(kFileNameExtension));
|
| + base::FilePath expected_file_path =
|
| + file_path_.AddExtension(kFileNameExtension);
|
| + EXPECT_CALL(*writer, Start(expected_file_path));
|
| + mock_audio_file_writer_ = writer;
|
| + return base::WrapUnique<AudioFileWriter>(writer);
|
| + }
|
| +
|
| + // Helper function that creates a recording helper.
|
| + std::unique_ptr<AudioDebugRecordingHelper> CreateRecordingHelper(
|
| + const AudioParameters& params,
|
| + base::OnceClosure on_destruction_closure) {
|
| + return base::MakeUnique<AudioDebugRecordingHelper>(
|
| + params, base::BindRepeating(
|
| + &AudioDebugRecordingHelperTest::CreateMockAudioFileWriter,
|
| + base::Unretained(this)),
|
| + message_loop_.task_runner(), std::move(on_destruction_closure));
|
| + }
|
| +
|
| + // Helper function that unsets the mock writer pointer after disabling.
|
| + void DisableDebugRecording(AudioDebugRecordingHelper* recording_helper) {
|
| + recording_helper->DisableDebugRecording();
|
| + mock_audio_file_writer_ = nullptr;
|
| + }
|
| +
|
| + MOCK_METHOD0(OnAudioDebugRecordingHelperDestruction, void());
|
| +
|
| + protected:
|
| + base::FilePath file_path_;
|
| +
|
| + // Pointer to the mock writer that the helper wraps. Set in
|
| + // CreateMockAudioFileWriter() and unset in DisableDebugRecording().
|
| + MockAudioFileWriter* mock_audio_file_writer_;
|
| +
|
| + base::TestMessageLoop message_loop_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(AudioDebugRecordingHelperTest);
|
| +};
|
| +
|
| +// Creates a helper with an on destrcution closure, and verifies that it's
|
| +// run.
|
| +TEST_F(AudioDebugRecordingHelperTest, TestDestructionClosure) {
|
| + const AudioParameters params;
|
| + std::unique_ptr<AudioDebugRecordingHelper> recording_helper =
|
| + CreateRecordingHelper(
|
| + params, base::BindOnce(&AudioDebugRecordingHelperTest::
|
| + OnAudioDebugRecordingHelperDestruction,
|
| + base::Unretained(this)));
|
| +
|
| + EXPECT_CALL(*this, OnAudioDebugRecordingHelperDestruction());
|
| +}
|
| +
|
| +// Verifies that disable can be called without being enabled.
|
| +TEST_F(AudioDebugRecordingHelperTest, OnlyDisable) {
|
| + const AudioParameters params;
|
| + std::unique_ptr<AudioDebugRecordingHelper> recording_helper =
|
| + CreateRecordingHelper(params, base::OnceClosure());
|
| +
|
| + recording_helper->DisableDebugRecording();
|
| +}
|
| +
|
| +TEST_F(AudioDebugRecordingHelperTest, EnableDisable) {
|
| + const AudioParameters params;
|
| + std::unique_ptr<AudioDebugRecordingHelper> recording_helper =
|
| + CreateRecordingHelper(params, base::OnceClosure());
|
| +
|
| + recording_helper->EnableDebugRecording(file_path_);
|
| + EXPECT_CALL(*mock_audio_file_writer_, Stop());
|
| + DisableDebugRecording(recording_helper.get());
|
| +
|
| + recording_helper->EnableDebugRecording(file_path_);
|
| + EXPECT_CALL(*mock_audio_file_writer_, Stop());
|
| + DisableDebugRecording(recording_helper.get());
|
| +}
|
| +
|
| +TEST_F(AudioDebugRecordingHelperTest, OnData) {
|
| + // Only channel layout and frames per buffer is used in the file writer and
|
| + // AudioBus, the other parameters are ignored.
|
| + const int number_of_frames = 100;
|
| + const AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR,
|
| + ChannelLayout::CHANNEL_LAYOUT_STEREO, 0, 0,
|
| + number_of_frames);
|
| +
|
| + // Setup some data.
|
| + const int number_of_samples = number_of_frames * params.channels();
|
| + const float step = std::numeric_limits<int16_t>::max() / number_of_frames;
|
| + std::unique_ptr<float[]> source_data(new float[number_of_samples]);
|
| + for (float i = 0; i < number_of_samples; ++i)
|
| + source_data[i] = i * step;
|
| + std::unique_ptr<AudioBus> audio_bus = AudioBus::Create(params);
|
| + audio_bus->FromInterleaved<Float32SampleTypeTraits>(source_data.get(),
|
| + number_of_frames);
|
| +
|
| + std::unique_ptr<AudioDebugRecordingHelper> recording_helper =
|
| + CreateRecordingHelper(params, base::OnceClosure());
|
| +
|
| + // Should not do anything.
|
| + recording_helper->OnData(audio_bus.get());
|
| +
|
| + recording_helper->EnableDebugRecording(file_path_);
|
| + mock_audio_file_writer_->SetReferenceData(audio_bus.get());
|
| +
|
| + EXPECT_CALL(*mock_audio_file_writer_, DoWrite(_));
|
| + recording_helper->OnData(audio_bus.get());
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_CALL(*mock_audio_file_writer_, Stop());
|
| + DisableDebugRecording(recording_helper.get());
|
| +
|
| + // Make sure we clear the loop before enabling again.
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // Enable again, this time with two OnData() calls, one OnData() call
|
| + // without running the message loop until after disabling, and one call after
|
| + // disabling.
|
| + recording_helper->EnableDebugRecording(file_path_);
|
| + mock_audio_file_writer_->SetReferenceData(audio_bus.get());
|
| +
|
| + EXPECT_CALL(*mock_audio_file_writer_, DoWrite(_)).Times(2);
|
| + recording_helper->OnData(audio_bus.get());
|
| + recording_helper->OnData(audio_bus.get());
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // This call should not yield a DoWrite() call on the mock, since the message
|
| + // loop isn't run until after disabling. WillWrite() is expected since
|
| + // recording is enabled.
|
| + recording_helper->OnData(audio_bus.get());
|
| +
|
| + EXPECT_CALL(*mock_audio_file_writer_, Stop());
|
| + DisableDebugRecording(recording_helper.get());
|
| +
|
| + // This call should not yield a DoWrite() call on the mock either.
|
| + recording_helper->OnData(audio_bus.get());
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +} // namespace media
|
|
|