| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/media/media_internals.h" | 5 #include "content/browser/media/media_internals.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/memory/scoped_ptr.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/message_loop/message_loop.h" | 9 #include "base/json/json_reader.h" |
| 10 #include "base/strings/stringprintf.h" | 10 #include "base/run_loop.h" |
| 11 #include "content/public/test/test_browser_thread.h" | 11 #include "base/strings/utf_string_conversions.h" |
| 12 #include "content/public/test/test_browser_thread_bundle.h" |
| 12 #include "media/audio/audio_parameters.h" | 13 #include "media/audio/audio_parameters.h" |
| 13 #include "media/base/channel_layout.h" | 14 #include "media/base/channel_layout.h" |
| 14 #include "testing/gmock/include/gmock/gmock.h" | |
| 15 #include "testing/gtest/include/gtest/gtest.h" | 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 | 16 |
| 17 namespace content { | |
| 18 namespace { | 17 namespace { |
| 19 | 18 const int kTestComponentID = 0; |
| 20 class MockObserverBaseClass { | 19 const char kTestInputDeviceID[] = "test-input-id"; |
| 21 public: | 20 const char kTestOutputDeviceID[] = "test-output-id"; |
| 22 ~MockObserverBaseClass() {} | |
| 23 virtual void OnUpdate(const string16& javascript) = 0; | |
| 24 }; | |
| 25 | |
| 26 class MockMediaInternalsObserver : public MockObserverBaseClass { | |
| 27 public: | |
| 28 virtual ~MockMediaInternalsObserver() {} | |
| 29 MOCK_METHOD1(OnUpdate, void(const string16& javascript)); | |
| 30 }; | |
| 31 | |
| 32 } // namespace | 21 } // namespace |
| 33 | 22 |
| 34 class MediaInternalsTest : public testing::Test { | 23 namespace content { |
| 24 |
| 25 class MediaInternalsTest |
| 26 : public testing::TestWithParam<media::AudioLogFactory::AudioComponent> { |
| 35 public: | 27 public: |
| 36 MediaInternalsTest() : io_thread_(BrowserThread::IO, &loop_) {} | 28 MediaInternalsTest() |
| 37 base::DictionaryValue* data() { | 29 : media_internals_(MediaInternals::GetInstance()), |
| 38 return &internals_->data_; | 30 update_cb_(base::Bind(&MediaInternalsTest::UpdateCallbackImpl, |
| 31 base::Unretained(this))), |
| 32 test_params_(media::AudioParameters::AUDIO_PCM_LINEAR, |
| 33 media::CHANNEL_LAYOUT_MONO, |
| 34 48000, |
| 35 16, |
| 36 128), |
| 37 test_component_(GetParam()), |
| 38 audio_log_(media_internals_->CreateAudioLog(test_component_)) { |
| 39 media_internals_->AddUpdateCallback(update_cb_); |
| 39 } | 40 } |
| 40 | 41 |
| 41 void DeleteItem(const std::string& item) { | 42 virtual ~MediaInternalsTest() { |
| 42 internals_->DeleteItem(item); | 43 media_internals_->RemoveUpdateCallback(update_cb_); |
| 43 } | |
| 44 | |
| 45 void UpdateItem(const std::string& item, const std::string& property, | |
| 46 base::Value* value) { | |
| 47 internals_->UpdateItem(std::string(), item, property, value); | |
| 48 } | |
| 49 | |
| 50 void SendUpdate(const std::string& function, base::Value* value) { | |
| 51 internals_->SendUpdate(function, value); | |
| 52 } | 44 } |
| 53 | 45 |
| 54 protected: | 46 protected: |
| 55 virtual void SetUp() { | 47 // Extracts and deserializes the JSON update data; merges into |update_data_|. |
| 56 internals_.reset(new MediaInternals()); | 48 void UpdateCallbackImpl(const string16& update) { |
| 49 // Each update string looks like "<JavaScript Function Name>({<JSON>});", to |
| 50 // use the JSON reader we need to strip out the JavaScript code. |
| 51 std::string utf8_update = base::UTF16ToUTF8(update); |
| 52 const std::string::size_type first_brace = utf8_update.find('{'); |
| 53 const std::string::size_type last_brace = utf8_update.rfind('}'); |
| 54 scoped_ptr<base::Value> output_value(base::JSONReader::Read( |
| 55 utf8_update.substr(first_brace, last_brace - first_brace + 1))); |
| 56 CHECK(output_value); |
| 57 |
| 58 base::DictionaryValue* output_dict = NULL; |
| 59 CHECK(output_value->GetAsDictionary(&output_dict)); |
| 60 update_data_.MergeDictionary(output_dict); |
| 57 } | 61 } |
| 58 | 62 |
| 59 base::MessageLoop loop_; | 63 void ExpectInt(const std::string& key, int expected_value) { |
| 60 TestBrowserThread io_thread_; | 64 int actual_value = 0; |
| 61 scoped_ptr<MediaInternals> internals_; | 65 ASSERT_TRUE(update_data_.GetInteger(key, &actual_value)); |
| 66 EXPECT_EQ(expected_value, actual_value); |
| 67 } |
| 68 |
| 69 void ExpectString(const std::string& key, const std::string& expected_value) { |
| 70 std::string actual_value; |
| 71 ASSERT_TRUE(update_data_.GetString(key, &actual_value)); |
| 72 EXPECT_EQ(expected_value, actual_value); |
| 73 } |
| 74 |
| 75 void ExpectStatus(const std::string& expected_value) { |
| 76 ExpectString("status", expected_value); |
| 77 } |
| 78 |
| 79 TestBrowserThreadBundle thread_bundle_; |
| 80 MediaInternals* const media_internals_; |
| 81 MediaInternals::UpdateCallback update_cb_; |
| 82 base::DictionaryValue update_data_; |
| 83 const media::AudioParameters test_params_; |
| 84 const media::AudioLogFactory::AudioComponent test_component_; |
| 85 scoped_ptr<media::AudioLog> audio_log_; |
| 62 }; | 86 }; |
| 63 | 87 |
| 64 TEST_F(MediaInternalsTest, AudioStreamCreatedSendsMessage) { | 88 TEST_P(MediaInternalsTest, AudioLogCreateStartStopErrorClose) { |
| 65 media::AudioParameters params = | 89 audio_log_->OnCreated( |
| 66 media::AudioParameters(media::AudioParameters::AUDIO_PCM_LINEAR, | 90 kTestComponentID, test_params_, kTestInputDeviceID, kTestOutputDeviceID); |
| 67 media::CHANNEL_LAYOUT_MONO, | 91 base::RunLoop().RunUntilIdle(); |
| 68 48000, | |
| 69 16, | |
| 70 129); | |
| 71 | 92 |
| 72 const int stream_id = 0; | 93 ExpectString("output_channel_layout", |
| 73 const std::string device_id = "test"; | 94 media::ChannelLayoutToString(test_params_.channel_layout())); |
| 74 const std::string name = | 95 ExpectInt("sample_rate", test_params_.sample_rate()); |
| 75 base::StringPrintf("audio_streams.%p:%d", this, stream_id); | 96 ExpectInt("frames_per_buffer", test_params_.frames_per_buffer()); |
| 97 ExpectInt("output_channels", test_params_.channels()); |
| 98 ExpectInt("input_channels", test_params_.input_channels()); |
| 99 ExpectString("output_device_id", kTestOutputDeviceID); |
| 100 ExpectString("input_device_id", kTestInputDeviceID); |
| 101 ExpectInt("component_id", kTestComponentID); |
| 102 ExpectInt("component_type", test_component_); |
| 103 ExpectStatus("created"); |
| 76 | 104 |
| 77 internals_->OnAudioStreamCreated(this, stream_id, params, device_id); | 105 // Verify OnStarted(). |
| 106 audio_log_->OnStarted(kTestComponentID); |
| 107 base::RunLoop().RunUntilIdle(); |
| 108 ExpectStatus("started"); |
| 78 | 109 |
| 79 std::string channel_layout; | 110 // Verify OnStopped(). |
| 80 data()->GetString(name + ".channel_layout", &channel_layout); | 111 audio_log_->OnStopped(kTestComponentID); |
| 81 EXPECT_EQ("MONO", channel_layout); | 112 base::RunLoop().RunUntilIdle(); |
| 113 ExpectStatus("stopped"); |
| 82 | 114 |
| 83 int sample_rate; | 115 // Verify OnError(). |
| 84 data()->GetInteger(name + ".sample_rate", &sample_rate); | 116 const char kErrorKey[] = "error_occurred"; |
| 85 EXPECT_EQ(params.sample_rate(), sample_rate); | 117 std::string no_value; |
| 118 ASSERT_FALSE(update_data_.GetString(kErrorKey, &no_value)); |
| 119 audio_log_->OnError(kTestComponentID); |
| 120 base::RunLoop().RunUntilIdle(); |
| 121 ExpectString(kErrorKey, "true"); |
| 86 | 122 |
| 87 int frames_per_buffer; | 123 // Verify OnClosed(). |
| 88 data()->GetInteger(name + ".frames_per_buffer", &frames_per_buffer); | 124 audio_log_->OnClosed(kTestComponentID); |
| 89 EXPECT_EQ(params.frames_per_buffer(), frames_per_buffer); | 125 base::RunLoop().RunUntilIdle(); |
| 90 | 126 ExpectStatus("closed"); |
| 91 int output_channels; | |
| 92 data()->GetInteger(name + ".output_channels", &output_channels); | |
| 93 EXPECT_EQ(params.channels(), output_channels); | |
| 94 | |
| 95 std::string device_id_out; | |
| 96 data()->GetString(name + ".input_device_id", &device_id_out); | |
| 97 EXPECT_EQ(device_id, device_id_out); | |
| 98 | |
| 99 int input_channels; | |
| 100 data()->GetInteger(name + ".input_channels", &input_channels); | |
| 101 EXPECT_EQ(params.input_channels(), input_channels); | |
| 102 } | 127 } |
| 103 | 128 |
| 104 TEST_F(MediaInternalsTest, UpdateAddsNewItem) { | 129 TEST_P(MediaInternalsTest, AudioLogCreateClose) { |
| 105 UpdateItem("some.item", "testing", new base::FundamentalValue(true)); | 130 audio_log_->OnCreated( |
| 106 bool testing = false; | 131 kTestComponentID, test_params_, kTestInputDeviceID, kTestOutputDeviceID); |
| 107 std::string id; | 132 base::RunLoop().RunUntilIdle(); |
| 133 ExpectStatus("created"); |
| 108 | 134 |
| 109 EXPECT_TRUE(data()->GetBoolean("some.item.testing", &testing)); | 135 audio_log_->OnClosed(kTestComponentID); |
| 110 EXPECT_TRUE(testing); | 136 base::RunLoop().RunUntilIdle(); |
| 111 | 137 ExpectStatus("closed"); |
| 112 EXPECT_TRUE(data()->GetString("some.item.id", &id)); | |
| 113 EXPECT_EQ(id, "some.item"); | |
| 114 } | 138 } |
| 115 | 139 |
| 116 TEST_F(MediaInternalsTest, UpdateModifiesExistingItem) { | 140 INSTANTIATE_TEST_CASE_P( |
| 117 UpdateItem("some.item", "testing", new base::FundamentalValue(true)); | 141 MediaInternalsTest, MediaInternalsTest, testing::Values( |
| 118 UpdateItem("some.item", "value", new base::FundamentalValue(5)); | 142 media::AudioLogFactory::AUDIO_INPUT_CONTROLLER, |
| 119 UpdateItem("some.item", "testing", new base::FundamentalValue(false)); | 143 media::AudioLogFactory::AUDIO_OUTPUT_CONTROLLER, |
| 120 bool testing = true; | 144 media::AudioLogFactory::AUDIO_OUTPUT_STREAM)); |
| 121 int value = 0; | |
| 122 std::string id; | |
| 123 | |
| 124 EXPECT_TRUE(data()->GetBoolean("some.item.testing", &testing)); | |
| 125 EXPECT_FALSE(testing); | |
| 126 | |
| 127 EXPECT_TRUE(data()->GetInteger("some.item.value", &value)); | |
| 128 EXPECT_EQ(value, 5); | |
| 129 | |
| 130 EXPECT_TRUE(data()->GetString("some.item.id", &id)); | |
| 131 EXPECT_EQ(id, "some.item"); | |
| 132 } | |
| 133 | |
| 134 TEST_F(MediaInternalsTest, ObserversReceiveNotifications) { | |
| 135 scoped_ptr<MockMediaInternalsObserver> observer( | |
| 136 new MockMediaInternalsObserver()); | |
| 137 | |
| 138 EXPECT_CALL(*observer.get(), OnUpdate(testing::_)).Times(1); | |
| 139 | |
| 140 MediaInternals::UpdateCallback callback = base::Bind( | |
| 141 &MockMediaInternalsObserver::OnUpdate, base::Unretained(observer.get())); | |
| 142 | |
| 143 internals_->AddUpdateCallback(callback); | |
| 144 SendUpdate("fn", data()); | |
| 145 } | |
| 146 | |
| 147 TEST_F(MediaInternalsTest, RemovedObserversReceiveNoNotifications) { | |
| 148 scoped_ptr<MockMediaInternalsObserver> observer( | |
| 149 new MockMediaInternalsObserver()); | |
| 150 | |
| 151 EXPECT_CALL(*observer.get(), OnUpdate(testing::_)).Times(0); | |
| 152 | |
| 153 MediaInternals::UpdateCallback callback = base::Bind( | |
| 154 &MockMediaInternalsObserver::OnUpdate, base::Unretained(observer.get())); | |
| 155 | |
| 156 internals_->AddUpdateCallback(callback); | |
| 157 internals_->RemoveUpdateCallback(callback); | |
| 158 SendUpdate("fn", data()); | |
| 159 } | |
| 160 | |
| 161 TEST_F(MediaInternalsTest, DeleteRemovesItem) { | |
| 162 base::Value* out; | |
| 163 | |
| 164 UpdateItem("some.item", "testing", base::Value::CreateNullValue()); | |
| 165 EXPECT_TRUE(data()->Get("some.item", &out)); | |
| 166 EXPECT_TRUE(data()->Get("some", &out)); | |
| 167 | |
| 168 DeleteItem("some.item"); | |
| 169 EXPECT_FALSE(data()->Get("some.item", &out)); | |
| 170 EXPECT_TRUE(data()->Get("some", &out)); | |
| 171 | |
| 172 DeleteItem("some"); | |
| 173 EXPECT_FALSE(data()->Get("some.item", &out)); | |
| 174 EXPECT_FALSE(data()->Get("some", &out)); | |
| 175 } | |
| 176 | 145 |
| 177 } // namespace content | 146 } // namespace content |
| OLD | NEW |