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/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
;
44 int g_saved_utterance_id
;
47 namespace extensions
{
49 class MockTtsPlatformImpl
: public TtsPlatformImpl
{
52 : should_fake_get_voices_(false),
55 virtual bool PlatformImplAvailable() {
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_
)
80 voice
.name
= "TestNativeVoice";
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(
97 base::Bind(&MockTtsPlatformImpl::SendEvent
, ptr_factory_
.GetWeakPtr(),
98 false, g_saved_utterance_id
, TTS_EVENT_END
, 0,
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()),
115 void SendEndEventWhenQueueNotEmpty(
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()),
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(
137 base::Bind(&MockTtsPlatformImpl::SendEvent
,
138 ptr_factory_
.GetWeakPtr(), false, utterance_id
,
139 TTS_EVENT_WORD
, i
, std::string()),
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::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
154 base::Bind(&MockTtsPlatformImpl::SendEvent
, ptr_factory_
.GetWeakPtr(),
155 true, utterance_id
, event_type
, char_index
, message
),
156 base::TimeDelta::FromMilliseconds(100));
160 controller
->OnTtsEvent(utterance_id
, event_type
, char_index
, message
);
164 bool should_fake_get_voices_
;
165 base::WeakPtrFactory
<MockTtsPlatformImpl
> ptr_factory_
;
168 class FakeNetworkOnlineStateForTest
: public net::NetworkChangeNotifier
{
170 explicit FakeNetworkOnlineStateForTest(bool online
) : online_(online
) {}
171 ~FakeNetworkOnlineStateForTest() override
{}
173 ConnectionType
GetCurrentConnectionType() const override
{
175 net::NetworkChangeNotifier::CONNECTION_ETHERNET
:
176 net::NetworkChangeNotifier::CONNECTION_NONE
;
181 DISALLOW_COPY_AND_ASSIGN(FakeNetworkOnlineStateForTest
);
184 class TtsApiTest
: public ExtensionApiTest
{
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();
199 ASSERT_EQ(Manifest::COMPONENT
,
200 content::Source
<const Extension
>(observer
.source())->location());
204 StrictMock
<MockTtsPlatformImpl
> mock_platform_impl_
;
207 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformSpeakOptionalArgs
) {
208 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
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
) {
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(_
, _
, _
, _
, _
))
241 Invoke(&mock_platform_impl_
,
242 &MockTtsPlatformImpl::SendEndEvent
),
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.
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", _
, _
, _
))
261 Invoke(&mock_platform_impl_
,
262 &MockTtsPlatformImpl::SendEndEvent
),
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.
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", _
, _
, _
))
284 Invoke(&mock_platform_impl_
,
285 &MockTtsPlatformImpl::SendEndEvent
),
287 ASSERT_TRUE(RunExtensionTest("tts/queue_interrupt")) << message_
;
290 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformSpeakEnqueue
) {
291 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
294 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
295 .WillOnce(Return(true));
296 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "text 1", _
, _
, _
))
298 Invoke(&mock_platform_impl_
,
299 &MockTtsPlatformImpl::SendEndEventWhenQueueNotEmpty
),
301 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "text 2", _
, _
, _
))
303 Invoke(&mock_platform_impl_
,
304 &MockTtsPlatformImpl::SendEndEvent
),
306 ASSERT_TRUE(RunExtensionTest("tts/enqueue")) << message_
;
309 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformSpeakError
) {
310 EXPECT_CALL(mock_platform_impl_
, IsSpeaking())
314 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
315 .WillOnce(Return(true));
316 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "first try", _
, _
, _
))
319 CreateFunctor(&mock_platform_impl_
,
320 &MockTtsPlatformImpl::SetErrorToEpicFail
)),
322 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
323 .WillOnce(Return(true));
324 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "second try", _
, _
, _
))
326 Invoke(&mock_platform_impl_
,
327 &MockTtsPlatformImpl::SendEndEvent
),
329 ASSERT_TRUE(RunExtensionTest("tts/speak_error")) << message_
;
332 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformWordCallbacks
) {
333 EXPECT_CALL(mock_platform_impl_
, IsSpeaking());
336 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
337 .WillOnce(Return(true));
338 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "one two three", _
, _
, _
))
340 Invoke(&mock_platform_impl_
,
341 &MockTtsPlatformImpl::SendWordEvents
),
342 Invoke(&mock_platform_impl_
,
343 &MockTtsPlatformImpl::SendEndEvent
),
345 ASSERT_TRUE(RunExtensionTest("tts/word_callbacks")) << message_
;
348 IN_PROC_BROWSER_TEST_F(TtsApiTest
, PlatformPauseResume
) {
349 EXPECT_CALL(mock_platform_impl_
, IsSpeaking())
353 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "test 1", _
, _
, _
))
355 Invoke(&mock_platform_impl_
,
356 &MockTtsPlatformImpl::SendEndEvent
),
358 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
359 .WillOnce(Return(true));
360 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "test 2", _
, _
, _
))
362 SaveArg
<0>(&g_saved_utterance_id
),
364 EXPECT_CALL(mock_platform_impl_
, Pause());
365 EXPECT_CALL(mock_platform_impl_
, Resume())
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.
377 EXPECT_CALL(mock_platform_impl_
, StopSpeaking()).WillOnce(Return(true));
378 ASSERT_TRUE(RunExtensionTest("tts/pause_speak_no_enqueue")) << message_
;
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())
390 EXPECT_CALL(mock_platform_impl_
, StopSpeaking())
391 .WillRepeatedly(Return(true));
395 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "native speech", _
, _
, _
))
397 Invoke(&mock_platform_impl_
,
398 &MockTtsPlatformImpl::SendEndEvent
),
400 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "native speech 2", _
, _
, _
))
402 Invoke(&mock_platform_impl_
,
403 &MockTtsPlatformImpl::SendEndEvent
),
405 EXPECT_CALL(mock_platform_impl_
, Speak(_
, "native speech 3", _
, _
, _
))
407 Invoke(&mock_platform_impl_
,
408 &MockTtsPlatformImpl::SendEndEvent
),
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