Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / speech / extension_api / tts_extension_apitest.cc
blob5bd1316a6ed33e84a15dc8c67397745134af161d
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include <vector>
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/location.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/single_thread_task_runner.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "chrome/browser/extensions/component_loader.h"
14 #include "chrome/browser/extensions/extension_apitest.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/speech/extension_api/tts_extension_api.h"
17 #include "chrome/browser/speech/tts_controller.h"
18 #include "chrome/browser/speech/tts_platform.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/test/test_utils.h"
22 #include "extensions/browser/extension_system.h"
23 #include "net/base/network_change_notifier.h"
24 #include "testing/gmock/include/gmock/gmock.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 // Needed for CreateFunctor.
28 #define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
29 #include "testing/gmock_mutant.h"
31 using ::testing::AnyNumber;
32 using ::testing::CreateFunctor;
33 using ::testing::DoAll;
34 using ::testing::Invoke;
35 using ::testing::InSequence;
36 using ::testing::InvokeWithoutArgs;
37 using ::testing::Return;
38 using ::testing::SaveArg;
39 using ::testing::SetArgPointee;
40 using ::testing::StrictMock;
41 using ::testing::_;
43 namespace {
44 int g_saved_utterance_id;
47 namespace extensions {
49 class MockTtsPlatformImpl : public TtsPlatformImpl {
50 public:
51 MockTtsPlatformImpl()
52 : should_fake_get_voices_(false),
53 ptr_factory_(this) {}
55 virtual bool PlatformImplAvailable() {
56 return true;
59 MOCK_METHOD5(Speak,
60 bool(int utterance_id,
61 const std::string& utterance,
62 const std::string& lang,
63 const VoiceData& voice,
64 const UtteranceContinuousParameters& params));
66 MOCK_METHOD0(StopSpeaking, bool(void));
68 MOCK_METHOD0(Pause, void(void));
70 MOCK_METHOD0(Resume, void(void));
72 MOCK_METHOD0(IsSpeaking, bool(void));
74 // Fake this method to add a native voice.
75 void GetVoices(std::vector<VoiceData>* voices) {
76 if (!should_fake_get_voices_)
77 return;
79 VoiceData voice;
80 voice.name = "TestNativeVoice";
81 voice.native = true;
82 voice.lang = "en-GB";
83 voice.events.insert(TTS_EVENT_START);
84 voice.events.insert(TTS_EVENT_END);
85 voices->push_back(voice);
88 void set_should_fake_get_voices(bool val) { should_fake_get_voices_ = val; }
90 void SetErrorToEpicFail() {
91 set_error("epic fail");
94 void SendEndEventOnSavedUtteranceId() {
95 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
96 FROM_HERE,
97 base::Bind(&MockTtsPlatformImpl::SendEvent, ptr_factory_.GetWeakPtr(),
98 false, g_saved_utterance_id, TTS_EVENT_END, 0,
99 std::string()),
100 base::TimeDelta());
103 void SendEndEvent(int utterance_id,
104 const std::string& utterance,
105 const std::string& lang,
106 const VoiceData& voice,
107 const UtteranceContinuousParameters& params) {
108 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
109 FROM_HERE, base::Bind(&MockTtsPlatformImpl::SendEvent,
110 ptr_factory_.GetWeakPtr(), false, utterance_id,
111 TTS_EVENT_END, utterance.size(), std::string()),
112 base::TimeDelta());
115 void SendEndEventWhenQueueNotEmpty(
116 int utterance_id,
117 const std::string& utterance,
118 const std::string& lang,
119 const VoiceData& voice,
120 const UtteranceContinuousParameters& params) {
121 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
122 FROM_HERE, base::Bind(&MockTtsPlatformImpl::SendEvent,
123 ptr_factory_.GetWeakPtr(), true, utterance_id,
124 TTS_EVENT_END, utterance.size(), std::string()),
125 base::TimeDelta());
128 void SendWordEvents(int utterance_id,
129 const std::string& utterance,
130 const std::string& lang,
131 const VoiceData& voice,
132 const UtteranceContinuousParameters& params) {
133 for (int i = 0; i < static_cast<int>(utterance.size()); i++) {
134 if (i == 0 || utterance[i - 1] == ' ') {
135 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
136 FROM_HERE,
137 base::Bind(&MockTtsPlatformImpl::SendEvent,
138 ptr_factory_.GetWeakPtr(), false, utterance_id,
139 TTS_EVENT_WORD, i, std::string()),
140 base::TimeDelta());
145 void SendEvent(bool wait_for_non_empty_queue,
146 int utterance_id,
147 TtsEventType event_type,
148 int char_index,
149 const std::string& message) {
150 TtsController* controller = TtsController::GetInstance();
151 if (wait_for_non_empty_queue && controller->QueueSize() == 0) {
152 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
153 FROM_HERE,
154 base::Bind(&MockTtsPlatformImpl::SendEvent, ptr_factory_.GetWeakPtr(),
155 true, utterance_id, event_type, char_index, message),
156 base::TimeDelta::FromMilliseconds(100));
157 return;
160 controller->OnTtsEvent(utterance_id, event_type, char_index, message);
163 private:
164 bool should_fake_get_voices_;
165 base::WeakPtrFactory<MockTtsPlatformImpl> ptr_factory_;
168 class FakeNetworkOnlineStateForTest : public net::NetworkChangeNotifier {
169 public:
170 explicit FakeNetworkOnlineStateForTest(bool online) : online_(online) {}
171 ~FakeNetworkOnlineStateForTest() override {}
173 ConnectionType GetCurrentConnectionType() const override {
174 return online_ ?
175 net::NetworkChangeNotifier::CONNECTION_ETHERNET :
176 net::NetworkChangeNotifier::CONNECTION_NONE;
179 private:
180 bool online_;
181 DISALLOW_COPY_AND_ASSIGN(FakeNetworkOnlineStateForTest);
184 class TtsApiTest : public ExtensionApiTest {
185 public:
186 virtual void SetUpInProcessBrowserTestFixture() {
187 ExtensionApiTest::SetUpInProcessBrowserTestFixture();
188 TtsController::GetInstance()->SetPlatformImpl(&mock_platform_impl_);
191 void AddNetworkSpeechSynthesisExtension() {
192 content::WindowedNotificationObserver observer(
193 NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
194 content::NotificationService::AllSources());
195 ExtensionService* service =
196 extensions::ExtensionSystem::Get(profile())->extension_service();
197 service->component_loader()->AddNetworkSpeechSynthesisExtension();
198 observer.Wait();
199 ASSERT_EQ(Manifest::COMPONENT,
200 content::Source<const Extension>(observer.source())->location());
203 protected:
204 StrictMock<MockTtsPlatformImpl> mock_platform_impl_;
207 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakOptionalArgs) {
208 EXPECT_CALL(mock_platform_impl_, IsSpeaking());
210 InSequence s;
211 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
212 .WillOnce(Return(true));
213 EXPECT_CALL(mock_platform_impl_, Speak(_, "", _, _, _))
214 .WillOnce(Return(true));
215 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
216 .WillOnce(Return(true));
217 EXPECT_CALL(mock_platform_impl_, Speak(_, "Alpha", _, _, _))
218 .WillOnce(Return(true));
219 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
220 .WillOnce(Return(true));
221 EXPECT_CALL(mock_platform_impl_, Speak(_, "Bravo", _, _, _))
222 .WillOnce(Return(true));
223 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
224 .WillOnce(Return(true));
225 EXPECT_CALL(mock_platform_impl_, Speak(_, "Charlie", _, _, _))
226 .WillOnce(Return(true));
227 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
228 .WillOnce(Return(true));
229 EXPECT_CALL(mock_platform_impl_, Speak(_, "Echo", _, _, _))
230 .WillOnce(Return(true));
231 ASSERT_TRUE(RunExtensionTest("tts/optional_args")) << message_;
234 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakFinishesImmediately) {
235 InSequence s;
236 EXPECT_CALL(mock_platform_impl_, IsSpeaking());
237 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
238 .WillOnce(Return(true));
239 EXPECT_CALL(mock_platform_impl_, Speak(_, _, _, _, _))
240 .WillOnce(DoAll(
241 Invoke(&mock_platform_impl_,
242 &MockTtsPlatformImpl::SendEndEvent),
243 Return(true)));
244 ASSERT_TRUE(RunExtensionTest("tts/speak_once")) << message_;
247 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakInterrupt) {
248 EXPECT_CALL(mock_platform_impl_, IsSpeaking());
250 // One utterance starts speaking, and then a second interrupts.
251 InSequence s;
252 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
253 .WillOnce(Return(true));
254 EXPECT_CALL(mock_platform_impl_, Speak(_, "text 1", _, _, _))
255 .WillOnce(Return(true));
256 // Expect the second utterance and allow it to finish.
257 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
258 .WillOnce(Return(true));
259 EXPECT_CALL(mock_platform_impl_, Speak(_, "text 2", _, _, _))
260 .WillOnce(DoAll(
261 Invoke(&mock_platform_impl_,
262 &MockTtsPlatformImpl::SendEndEvent),
263 Return(true)));
264 ASSERT_TRUE(RunExtensionTest("tts/interrupt")) << message_;
267 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakQueueInterrupt) {
268 EXPECT_CALL(mock_platform_impl_, IsSpeaking());
270 // In this test, two utterances are queued, and then a third
271 // interrupts. Speak(, _) never gets called on the second utterance.
272 InSequence s;
273 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
274 .WillOnce(Return(true));
275 EXPECT_CALL(mock_platform_impl_, Speak(_, "text 1", _, _, _))
276 .WillOnce(Return(true));
277 // Don't expect the second utterance, because it's queued up and the
278 // first never finishes.
279 // Expect the third utterance and allow it to finish successfully.
280 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
281 .WillOnce(Return(true));
282 EXPECT_CALL(mock_platform_impl_, Speak(_, "text 3", _, _, _))
283 .WillOnce(DoAll(
284 Invoke(&mock_platform_impl_,
285 &MockTtsPlatformImpl::SendEndEvent),
286 Return(true)));
287 ASSERT_TRUE(RunExtensionTest("tts/queue_interrupt")) << message_;
290 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakEnqueue) {
291 EXPECT_CALL(mock_platform_impl_, IsSpeaking());
293 InSequence s;
294 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
295 .WillOnce(Return(true));
296 EXPECT_CALL(mock_platform_impl_, Speak(_, "text 1", _, _, _))
297 .WillOnce(DoAll(
298 Invoke(&mock_platform_impl_,
299 &MockTtsPlatformImpl::SendEndEventWhenQueueNotEmpty),
300 Return(true)));
301 EXPECT_CALL(mock_platform_impl_, Speak(_, "text 2", _, _, _))
302 .WillOnce(DoAll(
303 Invoke(&mock_platform_impl_,
304 &MockTtsPlatformImpl::SendEndEvent),
305 Return(true)));
306 ASSERT_TRUE(RunExtensionTest("tts/enqueue")) << message_;
309 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakError) {
310 EXPECT_CALL(mock_platform_impl_, IsSpeaking())
311 .Times(AnyNumber());
313 InSequence s;
314 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
315 .WillOnce(Return(true));
316 EXPECT_CALL(mock_platform_impl_, Speak(_, "first try", _, _, _))
317 .WillOnce(DoAll(
318 InvokeWithoutArgs(
319 CreateFunctor(&mock_platform_impl_,
320 &MockTtsPlatformImpl::SetErrorToEpicFail)),
321 Return(false)));
322 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
323 .WillOnce(Return(true));
324 EXPECT_CALL(mock_platform_impl_, Speak(_, "second try", _, _, _))
325 .WillOnce(DoAll(
326 Invoke(&mock_platform_impl_,
327 &MockTtsPlatformImpl::SendEndEvent),
328 Return(true)));
329 ASSERT_TRUE(RunExtensionTest("tts/speak_error")) << message_;
332 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformWordCallbacks) {
333 EXPECT_CALL(mock_platform_impl_, IsSpeaking());
335 InSequence s;
336 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
337 .WillOnce(Return(true));
338 EXPECT_CALL(mock_platform_impl_, Speak(_, "one two three", _, _, _))
339 .WillOnce(DoAll(
340 Invoke(&mock_platform_impl_,
341 &MockTtsPlatformImpl::SendWordEvents),
342 Invoke(&mock_platform_impl_,
343 &MockTtsPlatformImpl::SendEndEvent),
344 Return(true)));
345 ASSERT_TRUE(RunExtensionTest("tts/word_callbacks")) << message_;
348 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformPauseResume) {
349 EXPECT_CALL(mock_platform_impl_, IsSpeaking())
350 .Times(AnyNumber());
352 InSequence s;
353 EXPECT_CALL(mock_platform_impl_, Speak(_, "test 1", _, _, _))
354 .WillOnce(DoAll(
355 Invoke(&mock_platform_impl_,
356 &MockTtsPlatformImpl::SendEndEvent),
357 Return(true)));
358 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
359 .WillOnce(Return(true));
360 EXPECT_CALL(mock_platform_impl_, Speak(_, "test 2", _, _, _))
361 .WillOnce(DoAll(
362 SaveArg<0>(&g_saved_utterance_id),
363 Return(true)));
364 EXPECT_CALL(mock_platform_impl_, Pause());
365 EXPECT_CALL(mock_platform_impl_, Resume())
366 .WillOnce(
367 InvokeWithoutArgs(
368 &mock_platform_impl_,
369 &MockTtsPlatformImpl::SendEndEventOnSavedUtteranceId));
370 ASSERT_TRUE(RunExtensionTest("tts/pause_resume")) << message_;
373 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformPauseSpeakNoEnqueue) {
374 // While paused, one utterance is enqueued, and then a second utterance that
375 // cannot be enqueued cancels both.
376 InSequence s;
377 EXPECT_CALL(mock_platform_impl_, StopSpeaking()).WillOnce(Return(true));
378 ASSERT_TRUE(RunExtensionTest("tts/pause_speak_no_enqueue")) << message_;
382 // TTS Engine tests.
385 IN_PROC_BROWSER_TEST_F(TtsApiTest, RegisterEngine) {
386 mock_platform_impl_.set_should_fake_get_voices(true);
388 EXPECT_CALL(mock_platform_impl_, IsSpeaking())
389 .Times(AnyNumber());
390 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
391 .WillRepeatedly(Return(true));
394 InSequence s;
395 EXPECT_CALL(mock_platform_impl_, Speak(_, "native speech", _, _, _))
396 .WillOnce(DoAll(
397 Invoke(&mock_platform_impl_,
398 &MockTtsPlatformImpl::SendEndEvent),
399 Return(true)));
400 EXPECT_CALL(mock_platform_impl_, Speak(_, "native speech 2", _, _, _))
401 .WillOnce(DoAll(
402 Invoke(&mock_platform_impl_,
403 &MockTtsPlatformImpl::SendEndEvent),
404 Return(true)));
405 EXPECT_CALL(mock_platform_impl_, Speak(_, "native speech 3", _, _, _))
406 .WillOnce(DoAll(
407 Invoke(&mock_platform_impl_,
408 &MockTtsPlatformImpl::SendEndEvent),
409 Return(true)));
412 ASSERT_TRUE(RunExtensionTest("tts_engine/register_engine")) << message_;
415 IN_PROC_BROWSER_TEST_F(TtsApiTest, EngineError) {
416 EXPECT_CALL(mock_platform_impl_, IsSpeaking());
417 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
418 .WillRepeatedly(Return(true));
420 ASSERT_TRUE(RunExtensionTest("tts_engine/engine_error")) << message_;
423 IN_PROC_BROWSER_TEST_F(TtsApiTest, EngineWordCallbacks) {
424 EXPECT_CALL(mock_platform_impl_, IsSpeaking());
425 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
426 .WillRepeatedly(Return(true));
428 ASSERT_TRUE(RunExtensionTest("tts_engine/engine_word_callbacks")) << message_;
431 IN_PROC_BROWSER_TEST_F(TtsApiTest, LangMatching) {
432 EXPECT_CALL(mock_platform_impl_, IsSpeaking());
433 EXPECT_CALL(mock_platform_impl_, StopSpeaking())
434 .WillRepeatedly(Return(true));
436 ASSERT_TRUE(RunExtensionTest("tts_engine/lang_matching")) << message_;
439 IN_PROC_BROWSER_TEST_F(TtsApiTest, NetworkSpeechEngine) {
440 // Simulate online network state.
441 net::NetworkChangeNotifier::DisableForTest disable_for_test;
442 FakeNetworkOnlineStateForTest fake_online_state(true);
444 ASSERT_NO_FATAL_FAILURE(AddNetworkSpeechSynthesisExtension());
445 ASSERT_TRUE(RunExtensionTest("tts_engine/network_speech_engine")) << message_;
448 IN_PROC_BROWSER_TEST_F(TtsApiTest, NoNetworkSpeechEngineWhenOffline) {
449 // Simulate offline network state.
450 net::NetworkChangeNotifier::DisableForTest disable_for_test;
451 FakeNetworkOnlineStateForTest fake_online_state(false);
453 ASSERT_NO_FATAL_FAILURE(AddNetworkSpeechSynthesisExtension());
454 // Test should fail when offline.
455 ASSERT_FALSE(RunExtensionTest("tts_engine/network_speech_engine"));
458 // http://crbug.com/122474
459 IN_PROC_BROWSER_TEST_F(TtsApiTest, EngineApi) {
460 ASSERT_TRUE(RunExtensionTest("tts_engine/engine_api")) << message_;
463 } // namespace extensions