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.
8 #include "base/command_line.h"
9 #include "base/memory/weak_ptr.h"
10 #include "base/message_loop/message_loop.h"
11 #include "chrome/browser/extensions/component_loader.h"
12 #include "chrome/browser/extensions/extension_apitest.h"
13 #include "chrome/browser/extensions/extension_service.h"
14 #include "chrome/browser/speech/extension_api/tts_extension_api.h"
15 #include "chrome/browser/speech/tts_controller.h"
16 #include "chrome/browser/speech/tts_platform.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "extensions/browser/extension_system.h"
19 #include "net/base/network_change_notifier.h"
20 #include "testing/gmock/include/gmock/gmock.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 // Needed for CreateFunctor.
24 #define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
25 #include "testing/gmock_mutant.h"
27 using ::testing::AnyNumber
;
28 using ::testing::CreateFunctor
;
29 using ::testing::DoAll
;
30 using ::testing::Invoke
;
31 using ::testing::InSequence
;
32 using ::testing::InvokeWithoutArgs
;
33 using ::testing::Return
;
34 using ::testing::SaveArg
;
35 using ::testing::SetArgPointee
;
36 using ::testing::StrictMock
;
40 int g_saved_utterance_id
;
43 namespace extensions
{
45 class MockTtsPlatformImpl
: public TtsPlatformImpl
{
48 : should_fake_get_voices_(false),
51 virtual bool PlatformImplAvailable() {
56 bool(int utterance_id
,
57 const std::string
& utterance
,
58 const std::string
& lang
,
59 const VoiceData
& voice
,
60 const UtteranceContinuousParameters
& params
));
62 MOCK_METHOD0(StopSpeaking
, bool(void));
64 MOCK_METHOD0(Pause
, void(void));
66 MOCK_METHOD0(Resume
, void(void));
68 MOCK_METHOD0(IsSpeaking
, bool(void));
70 // Fake this method to add a native voice.
71 void GetVoices(std::vector
<VoiceData
>* voices
) {
72 if (!should_fake_get_voices_
)
76 voice
.name
= "TestNativeVoice";
79 voice
.events
.insert(TTS_EVENT_START
);
80 voice
.events
.insert(TTS_EVENT_END
);
81 voices
->push_back(voice
);
84 void set_should_fake_get_voices(bool val
) { should_fake_get_voices_
= val
; }
86 void SetErrorToEpicFail() {
87 set_error("epic fail");
90 void SendEndEventOnSavedUtteranceId() {
91 base::MessageLoop::current()->PostDelayedTask(
92 FROM_HERE
, base::Bind(
93 &MockTtsPlatformImpl::SendEvent
,
94 ptr_factory_
.GetWeakPtr(),
95 false, g_saved_utterance_id
, TTS_EVENT_END
, 0, std::string()),
99 void SendEndEvent(int utterance_id
,
100 const std::string
& utterance
,
101 const std::string
& lang
,
102 const VoiceData
& voice
,
103 const UtteranceContinuousParameters
& params
) {
104 base::MessageLoop::current()->PostDelayedTask(
105 FROM_HERE
, base::Bind(
106 &MockTtsPlatformImpl::SendEvent
,
107 ptr_factory_
.GetWeakPtr(),
108 false, utterance_id
, TTS_EVENT_END
, utterance
.size(),
113 void SendEndEventWhenQueueNotEmpty(
115 const std::string
& utterance
,
116 const std::string
& lang
,
117 const VoiceData
& voice
,
118 const UtteranceContinuousParameters
& params
) {
119 base::MessageLoop::current()->PostDelayedTask(
120 FROM_HERE
, base::Bind(
121 &MockTtsPlatformImpl::SendEvent
,
122 ptr_factory_
.GetWeakPtr(),
123 true, utterance_id
, TTS_EVENT_END
, utterance
.size(), std::string()),
127 void SendWordEvents(int utterance_id
,
128 const std::string
& utterance
,
129 const std::string
& lang
,
130 const VoiceData
& voice
,
131 const UtteranceContinuousParameters
& params
) {
132 for (int i
= 0; i
< static_cast<int>(utterance
.size()); i
++) {
133 if (i
== 0 || utterance
[i
- 1] == ' ') {
134 base::MessageLoop::current()->PostDelayedTask(
135 FROM_HERE
, base::Bind(
136 &MockTtsPlatformImpl::SendEvent
,
137 ptr_factory_
.GetWeakPtr(),
138 false, utterance_id
, TTS_EVENT_WORD
, i
,
145 void SendEvent(bool wait_for_non_empty_queue
,
147 TtsEventType event_type
,
149 const std::string
& message
) {
150 TtsController
* controller
= TtsController::GetInstance();
151 if (wait_for_non_empty_queue
&& controller
->QueueSize() == 0) {
152 base::MessageLoop::current()->PostDelayedTask(
153 FROM_HERE
, base::Bind(
154 &MockTtsPlatformImpl::SendEvent
,
155 ptr_factory_
.GetWeakPtr(),
156 true, utterance_id
, event_type
, char_index
, message
),
157 base::TimeDelta::FromMilliseconds(100));
161 controller
->OnTtsEvent(utterance_id
, event_type
, char_index
, message
);
165 bool should_fake_get_voices_
;
166 base::WeakPtrFactory
<MockTtsPlatformImpl
> ptr_factory_
;
169 class FakeNetworkOnlineStateForTest
: public net::NetworkChangeNotifier
{
171 explicit FakeNetworkOnlineStateForTest(bool online
) : online_(online
) {}
172 ~FakeNetworkOnlineStateForTest() override
{}
174 ConnectionType
GetCurrentConnectionType() const override
{
176 net::NetworkChangeNotifier::CONNECTION_ETHERNET
:
177 net::NetworkChangeNotifier::CONNECTION_NONE
;
182 DISALLOW_COPY_AND_ASSIGN(FakeNetworkOnlineStateForTest
);
185 class TtsApiTest
: public ExtensionApiTest
{
187 virtual void SetUpInProcessBrowserTestFixture() {
188 ExtensionApiTest::SetUpInProcessBrowserTestFixture();
189 TtsController::GetInstance()->SetPlatformImpl(&mock_platform_impl_
);
193 StrictMock
<MockTtsPlatformImpl
> mock_platform_impl_
;
196 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformSpeakOptionalArgs
) {
197 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
200 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
201 .WillOnce(Return(true));
202 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "", _
, _
, _
))
203 .WillOnce(Return(true));
204 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
205 .WillOnce(Return(true));
206 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "Alpha", _
, _
, _
))
207 .WillOnce(Return(true));
208 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
209 .WillOnce(Return(true));
210 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "Bravo", _
, _
, _
))
211 .WillOnce(Return(true));
212 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
213 .WillOnce(Return(true));
214 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "Charlie", _
, _
, _
))
215 .WillOnce(Return(true));
216 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
217 .WillOnce(Return(true));
218 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "Echo", _
, _
, _
))
219 .WillOnce(Return(true));
220 ASSERT_TRUE(RunExtensionTest("tts/optional_args")) << message_
;
223 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformSpeakFinishesImmediately
) {
225 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
226 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
227 .WillOnce(Return(true));
228 EXPECT_CALL(mock_platform_impl_
, Speak(_
, _
, _
, _
, _
))
230 Invoke(&mock_platform_impl_
,
231 &MockTtsPlatformImpl::SendEndEvent
),
233 ASSERT_TRUE(RunExtensionTest("tts/speak_once")) << message_
;
236 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformSpeakInterrupt
) {
237 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
239 // One utterance starts speaking, and then a second interrupts.
241 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
242 .WillOnce(Return(true));
243 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "text 1", _
, _
, _
))
244 .WillOnce(Return(true));
245 // Expect the second utterance and allow it to finish.
246 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
247 .WillOnce(Return(true));
248 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "text 2", _
, _
, _
))
250 Invoke(&mock_platform_impl_
,
251 &MockTtsPlatformImpl::SendEndEvent
),
253 ASSERT_TRUE(RunExtensionTest("tts/interrupt")) << message_
;
256 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformSpeakQueueInterrupt
) {
257 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
259 // In this test, two utterances are queued, and then a third
260 // interrupts. Speak(, _) never gets called on the second utterance.
262 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
263 .WillOnce(Return(true));
264 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "text 1", _
, _
, _
))
265 .WillOnce(Return(true));
266 // Don't expect the second utterance, because it's queued up and the
267 // first never finishes.
268 // Expect the third utterance and allow it to finish successfully.
269 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
270 .WillOnce(Return(true));
271 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "text 3", _
, _
, _
))
273 Invoke(&mock_platform_impl_
,
274 &MockTtsPlatformImpl::SendEndEvent
),
276 ASSERT_TRUE(RunExtensionTest("tts/queue_interrupt")) << message_
;
279 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformSpeakEnqueue
) {
280 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
283 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
284 .WillOnce(Return(true));
285 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "text 1", _
, _
, _
))
287 Invoke(&mock_platform_impl_
,
288 &MockTtsPlatformImpl::SendEndEventWhenQueueNotEmpty
),
290 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "text 2", _
, _
, _
))
292 Invoke(&mock_platform_impl_
,
293 &MockTtsPlatformImpl::SendEndEvent
),
295 ASSERT_TRUE(RunExtensionTest("tts/enqueue")) << message_
;
298 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformSpeakError
) {
299 EXPECT_CALL(mock_platform_impl_
, IsSpeaking())
303 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
304 .WillOnce(Return(true));
305 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "first try", _
, _
, _
))
308 CreateFunctor(&mock_platform_impl_
,
309 &MockTtsPlatformImpl::SetErrorToEpicFail
)),
311 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
312 .WillOnce(Return(true));
313 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "second try", _
, _
, _
))
315 Invoke(&mock_platform_impl_
,
316 &MockTtsPlatformImpl::SendEndEvent
),
318 ASSERT_TRUE(RunExtensionTest("tts/speak_error")) << message_
;
321 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformWordCallbacks
) {
322 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
325 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
326 .WillOnce(Return(true));
327 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "one two three", _
, _
, _
))
329 Invoke(&mock_platform_impl_
,
330 &MockTtsPlatformImpl::SendWordEvents
),
331 Invoke(&mock_platform_impl_
,
332 &MockTtsPlatformImpl::SendEndEvent
),
334 ASSERT_TRUE(RunExtensionTest("tts/word_callbacks")) << message_
;
337 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformPauseResume
) {
338 EXPECT_CALL(mock_platform_impl_
, IsSpeaking())
342 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "test 1", _
, _
, _
))
344 Invoke(&mock_platform_impl_
,
345 &MockTtsPlatformImpl::SendEndEvent
),
347 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
348 .WillOnce(Return(true));
349 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "test 2", _
, _
, _
))
351 SaveArg
<0>(&g_saved_utterance_id
),
353 EXPECT_CALL(mock_platform_impl_
, Pause());
354 EXPECT_CALL(mock_platform_impl_
, Resume())
357 &mock_platform_impl_
,
358 &MockTtsPlatformImpl::SendEndEventOnSavedUtteranceId
));
359 ASSERT_TRUE(RunExtensionTest("tts/pause_resume")) << message_
;
366 IN_PROC_BROWSER_TEST_F(TtsApiTest
, RegisterEngine
) {
367 mock_platform_impl_
.set_should_fake_get_voices(true);
369 EXPECT_CALL(mock_platform_impl_
, IsSpeaking())
371 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
372 .WillRepeatedly(Return(true));
376 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "native speech", _
, _
, _
))
378 Invoke(&mock_platform_impl_
,
379 &MockTtsPlatformImpl::SendEndEvent
),
381 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "native speech 2", _
, _
, _
))
383 Invoke(&mock_platform_impl_
,
384 &MockTtsPlatformImpl::SendEndEvent
),
386 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "native speech 3", _
, _
, _
))
388 Invoke(&mock_platform_impl_
,
389 &MockTtsPlatformImpl::SendEndEvent
),
393 ASSERT_TRUE(RunExtensionTest("tts_engine/register_engine")) << message_
;
396 IN_PROC_BROWSER_TEST_F(TtsApiTest
, EngineError
) {
397 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
398 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
399 .WillRepeatedly(Return(true));
401 ASSERT_TRUE(RunExtensionTest("tts_engine/engine_error")) << message_
;
404 IN_PROC_BROWSER_TEST_F(TtsApiTest
, EngineWordCallbacks
) {
405 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
406 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
407 .WillRepeatedly(Return(true));
409 ASSERT_TRUE(RunExtensionTest("tts_engine/engine_word_callbacks")) << message_
;
412 IN_PROC_BROWSER_TEST_F(TtsApiTest
, LangMatching
) {
413 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
414 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
415 .WillRepeatedly(Return(true));
417 ASSERT_TRUE(RunExtensionTest("tts_engine/lang_matching")) << message_
;
420 IN_PROC_BROWSER_TEST_F(TtsApiTest
, NetworkSpeechEngine
) {
421 // Simulate online network state.
422 net::NetworkChangeNotifier::DisableForTest disable_for_test
;
423 FakeNetworkOnlineStateForTest
fake_online_state(true);
425 ExtensionService
* service
= extensions::ExtensionSystem::Get(
426 profile())->extension_service();
427 service
->component_loader()->AddNetworkSpeechSynthesisExtension();
428 ASSERT_TRUE(RunExtensionTest("tts_engine/network_speech_engine")) << message_
;
431 IN_PROC_BROWSER_TEST_F(TtsApiTest
, NoNetworkSpeechEngineWhenOffline
) {
432 // Simulate offline network state.
433 net::NetworkChangeNotifier::DisableForTest disable_for_test
;
434 FakeNetworkOnlineStateForTest
fake_online_state(false);
436 ExtensionService
* service
= extensions::ExtensionSystem::Get(
437 profile())->extension_service();
438 service
->component_loader()->AddNetworkSpeechSynthesisExtension();
439 // Test should fail when offline.
440 ASSERT_FALSE(RunExtensionTest("tts_engine/network_speech_engine"));
443 // http://crbug.com/122474
444 IN_PROC_BROWSER_TEST_F(TtsApiTest
, EngineApi
) {
445 ASSERT_TRUE(RunExtensionTest("tts_engine/engine_api")) << message_
;
448 } // namespace extensions