• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include <vector>
6 
7 #include "base/bind.h"
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"
22 
23 // Needed for CreateFunctor.
24 #define GMOCK_MUTANT_INCLUDE_LATE_OBJECT_BINDING
25 #include "testing/gmock_mutant.h"
26 
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;
37 using ::testing::_;
38 
39 namespace {
40 int g_saved_utterance_id;
41 }
42 
43 namespace extensions {
44 
45 class MockTtsPlatformImpl : public TtsPlatformImpl {
46  public:
MockTtsPlatformImpl()47   MockTtsPlatformImpl()
48       : ptr_factory_(this),
49         should_fake_get_voices_(false) {}
50 
PlatformImplAvailable()51   virtual bool PlatformImplAvailable() {
52     return true;
53   }
54 
55   MOCK_METHOD5(Speak,
56                bool(int utterance_id,
57                     const std::string& utterance,
58                     const std::string& lang,
59                     const VoiceData& voice,
60                     const UtteranceContinuousParameters& params));
61 
62   MOCK_METHOD0(StopSpeaking, bool(void));
63 
64   MOCK_METHOD0(Pause, void(void));
65 
66   MOCK_METHOD0(Resume, void(void));
67 
68   MOCK_METHOD0(IsSpeaking, bool(void));
69 
70   // Fake this method to add a native voice.
GetVoices(std::vector<VoiceData> * voices)71   void GetVoices(std::vector<VoiceData>* voices) {
72     if (!should_fake_get_voices_)
73       return;
74 
75     VoiceData voice;
76     voice.name = "TestNativeVoice";
77     voice.native = true;
78     voice.lang = "en-GB";
79     voice.events.insert(TTS_EVENT_START);
80     voice.events.insert(TTS_EVENT_END);
81     voices->push_back(voice);
82   }
83 
set_should_fake_get_voices(bool val)84   void set_should_fake_get_voices(bool val) { should_fake_get_voices_ = val; }
85 
SetErrorToEpicFail()86   void SetErrorToEpicFail() {
87     set_error("epic fail");
88   }
89 
SendEndEventOnSavedUtteranceId()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()),
96         base::TimeDelta());
97   }
98 
SendEndEvent(int utterance_id,const std::string & utterance,const std::string & lang,const VoiceData & voice,const UtteranceContinuousParameters & params)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(),
109             std::string()),
110         base::TimeDelta());
111   }
112 
SendEndEventWhenQueueNotEmpty(int utterance_id,const std::string & utterance,const std::string & lang,const VoiceData & voice,const UtteranceContinuousParameters & params)113   void SendEndEventWhenQueueNotEmpty(
114       int utterance_id,
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()),
124         base::TimeDelta());
125   }
126 
SendWordEvents(int utterance_id,const std::string & utterance,const std::string & lang,const VoiceData & voice,const UtteranceContinuousParameters & params)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,
139                 std::string()),
140             base::TimeDelta());
141       }
142     }
143   }
144 
SendEvent(bool wait_for_non_empty_queue,int utterance_id,TtsEventType event_type,int char_index,const std::string & message)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::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));
158       return;
159     }
160 
161     controller->OnTtsEvent(utterance_id, event_type, char_index, message);
162   }
163 
164  private:
165   base::WeakPtrFactory<MockTtsPlatformImpl> ptr_factory_;
166   bool should_fake_get_voices_;
167 };
168 
169 class FakeNetworkOnlineStateForTest : public net::NetworkChangeNotifier {
170  public:
FakeNetworkOnlineStateForTest(bool online)171   explicit FakeNetworkOnlineStateForTest(bool online) : online_(online) {}
~FakeNetworkOnlineStateForTest()172   virtual ~FakeNetworkOnlineStateForTest() {}
173 
GetCurrentConnectionType() const174   virtual ConnectionType GetCurrentConnectionType() const OVERRIDE {
175     return online_ ?
176         net::NetworkChangeNotifier::CONNECTION_ETHERNET :
177         net::NetworkChangeNotifier::CONNECTION_NONE;
178   }
179 
180  private:
181   bool online_;
182   DISALLOW_COPY_AND_ASSIGN(FakeNetworkOnlineStateForTest);
183 };
184 
185 class TtsApiTest : public ExtensionApiTest {
186  public:
SetUpInProcessBrowserTestFixture()187   virtual void SetUpInProcessBrowserTestFixture() {
188     ExtensionApiTest::SetUpInProcessBrowserTestFixture();
189     TtsController::GetInstance()->SetPlatformImpl(&mock_platform_impl_);
190   }
191 
192  protected:
193   StrictMock<MockTtsPlatformImpl> mock_platform_impl_;
194 };
195 
IN_PROC_BROWSER_TEST_F(TtsApiTest,PlatformSpeakOptionalArgs)196 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakOptionalArgs) {
197   EXPECT_CALL(mock_platform_impl_, IsSpeaking());
198 
199   InSequence s;
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_;
221 }
222 
IN_PROC_BROWSER_TEST_F(TtsApiTest,PlatformSpeakFinishesImmediately)223 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakFinishesImmediately) {
224   InSequence s;
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(_, _, _, _, _))
229       .WillOnce(DoAll(
230           Invoke(&mock_platform_impl_,
231                  &MockTtsPlatformImpl::SendEndEvent),
232           Return(true)));
233   ASSERT_TRUE(RunExtensionTest("tts/speak_once")) << message_;
234 }
235 
IN_PROC_BROWSER_TEST_F(TtsApiTest,PlatformSpeakInterrupt)236 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakInterrupt) {
237   EXPECT_CALL(mock_platform_impl_, IsSpeaking());
238 
239   // One utterance starts speaking, and then a second interrupts.
240   InSequence s;
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", _, _, _))
249       .WillOnce(DoAll(
250           Invoke(&mock_platform_impl_,
251                  &MockTtsPlatformImpl::SendEndEvent),
252           Return(true)));
253   ASSERT_TRUE(RunExtensionTest("tts/interrupt")) << message_;
254 }
255 
IN_PROC_BROWSER_TEST_F(TtsApiTest,PlatformSpeakQueueInterrupt)256 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakQueueInterrupt) {
257   EXPECT_CALL(mock_platform_impl_, IsSpeaking());
258 
259   // In this test, two utterances are queued, and then a third
260   // interrupts. Speak(, _) never gets called on the second utterance.
261   InSequence s;
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", _, _, _))
272       .WillOnce(DoAll(
273           Invoke(&mock_platform_impl_,
274                  &MockTtsPlatformImpl::SendEndEvent),
275           Return(true)));
276   ASSERT_TRUE(RunExtensionTest("tts/queue_interrupt")) << message_;
277 }
278 
IN_PROC_BROWSER_TEST_F(TtsApiTest,PlatformSpeakEnqueue)279 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakEnqueue) {
280   EXPECT_CALL(mock_platform_impl_, IsSpeaking());
281 
282   InSequence s;
283   EXPECT_CALL(mock_platform_impl_, StopSpeaking())
284       .WillOnce(Return(true));
285   EXPECT_CALL(mock_platform_impl_, Speak(_, "text 1", _, _, _))
286       .WillOnce(DoAll(
287           Invoke(&mock_platform_impl_,
288                  &MockTtsPlatformImpl::SendEndEventWhenQueueNotEmpty),
289           Return(true)));
290   EXPECT_CALL(mock_platform_impl_, Speak(_, "text 2", _, _, _))
291       .WillOnce(DoAll(
292           Invoke(&mock_platform_impl_,
293                  &MockTtsPlatformImpl::SendEndEvent),
294           Return(true)));
295   ASSERT_TRUE(RunExtensionTest("tts/enqueue")) << message_;
296 }
297 
IN_PROC_BROWSER_TEST_F(TtsApiTest,PlatformSpeakError)298 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformSpeakError) {
299   EXPECT_CALL(mock_platform_impl_, IsSpeaking())
300       .Times(AnyNumber());
301 
302   InSequence s;
303   EXPECT_CALL(mock_platform_impl_, StopSpeaking())
304       .WillOnce(Return(true));
305   EXPECT_CALL(mock_platform_impl_, Speak(_, "first try", _, _, _))
306       .WillOnce(DoAll(
307           InvokeWithoutArgs(
308               CreateFunctor(&mock_platform_impl_,
309                             &MockTtsPlatformImpl::SetErrorToEpicFail)),
310           Return(false)));
311   EXPECT_CALL(mock_platform_impl_, StopSpeaking())
312       .WillOnce(Return(true));
313   EXPECT_CALL(mock_platform_impl_, Speak(_, "second try", _, _, _))
314       .WillOnce(DoAll(
315           Invoke(&mock_platform_impl_,
316                  &MockTtsPlatformImpl::SendEndEvent),
317           Return(true)));
318   ASSERT_TRUE(RunExtensionTest("tts/speak_error")) << message_;
319 }
320 
IN_PROC_BROWSER_TEST_F(TtsApiTest,PlatformWordCallbacks)321 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformWordCallbacks) {
322   EXPECT_CALL(mock_platform_impl_, IsSpeaking());
323 
324   InSequence s;
325   EXPECT_CALL(mock_platform_impl_, StopSpeaking())
326       .WillOnce(Return(true));
327   EXPECT_CALL(mock_platform_impl_, Speak(_, "one two three", _, _, _))
328       .WillOnce(DoAll(
329           Invoke(&mock_platform_impl_,
330                  &MockTtsPlatformImpl::SendWordEvents),
331           Invoke(&mock_platform_impl_,
332                  &MockTtsPlatformImpl::SendEndEvent),
333           Return(true)));
334   ASSERT_TRUE(RunExtensionTest("tts/word_callbacks")) << message_;
335 }
336 
IN_PROC_BROWSER_TEST_F(TtsApiTest,PlatformPauseResume)337 IN_PROC_BROWSER_TEST_F(TtsApiTest, PlatformPauseResume) {
338   EXPECT_CALL(mock_platform_impl_, IsSpeaking())
339       .Times(AnyNumber());
340 
341   InSequence s;
342   EXPECT_CALL(mock_platform_impl_, Speak(_, "test 1", _, _, _))
343       .WillOnce(DoAll(
344           Invoke(&mock_platform_impl_,
345                  &MockTtsPlatformImpl::SendEndEvent),
346           Return(true)));
347   EXPECT_CALL(mock_platform_impl_, StopSpeaking())
348       .WillOnce(Return(true));
349   EXPECT_CALL(mock_platform_impl_, Speak(_, "test 2", _, _, _))
350       .WillOnce(DoAll(
351           SaveArg<0>(&g_saved_utterance_id),
352           Return(true)));
353   EXPECT_CALL(mock_platform_impl_, Pause());
354   EXPECT_CALL(mock_platform_impl_, Resume())
355       .WillOnce(
356           InvokeWithoutArgs(
357               &mock_platform_impl_,
358               &MockTtsPlatformImpl::SendEndEventOnSavedUtteranceId));
359   ASSERT_TRUE(RunExtensionTest("tts/pause_resume")) << message_;
360 }
361 
362 //
363 // TTS Engine tests.
364 //
365 
IN_PROC_BROWSER_TEST_F(TtsApiTest,RegisterEngine)366 IN_PROC_BROWSER_TEST_F(TtsApiTest, RegisterEngine) {
367   mock_platform_impl_.set_should_fake_get_voices(true);
368 
369   EXPECT_CALL(mock_platform_impl_, IsSpeaking())
370       .Times(AnyNumber());
371   EXPECT_CALL(mock_platform_impl_, StopSpeaking())
372       .WillRepeatedly(Return(true));
373 
374   {
375     InSequence s;
376     EXPECT_CALL(mock_platform_impl_, Speak(_, "native speech", _, _, _))
377       .WillOnce(DoAll(
378           Invoke(&mock_platform_impl_,
379                  &MockTtsPlatformImpl::SendEndEvent),
380           Return(true)));
381     EXPECT_CALL(mock_platform_impl_, Speak(_, "native speech 2", _, _, _))
382       .WillOnce(DoAll(
383           Invoke(&mock_platform_impl_,
384                  &MockTtsPlatformImpl::SendEndEvent),
385           Return(true)));
386     EXPECT_CALL(mock_platform_impl_, Speak(_, "native speech 3", _, _, _))
387       .WillOnce(DoAll(
388           Invoke(&mock_platform_impl_,
389                  &MockTtsPlatformImpl::SendEndEvent),
390           Return(true)));
391   }
392 
393   ASSERT_TRUE(RunExtensionTest("tts_engine/register_engine")) << message_;
394 }
395 
IN_PROC_BROWSER_TEST_F(TtsApiTest,EngineError)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));
400 
401   ASSERT_TRUE(RunExtensionTest("tts_engine/engine_error")) << message_;
402 }
403 
IN_PROC_BROWSER_TEST_F(TtsApiTest,EngineWordCallbacks)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));
408 
409   ASSERT_TRUE(RunExtensionTest("tts_engine/engine_word_callbacks")) << message_;
410 }
411 
IN_PROC_BROWSER_TEST_F(TtsApiTest,LangMatching)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));
416 
417   ASSERT_TRUE(RunExtensionTest("tts_engine/lang_matching")) << message_;
418 }
419 
IN_PROC_BROWSER_TEST_F(TtsApiTest,NetworkSpeechEngine)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);
424 
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_;
429 }
430 
IN_PROC_BROWSER_TEST_F(TtsApiTest,NoNetworkSpeechEngineWhenOffline)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);
435 
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"));
441 }
442 
443 // http://crbug.com/122474
IN_PROC_BROWSER_TEST_F(TtsApiTest,EngineApi)444 IN_PROC_BROWSER_TEST_F(TtsApiTest, EngineApi) {
445   ASSERT_TRUE(RunExtensionTest("tts_engine/engine_api")) << message_;
446 }
447 
448 }  // namespace extensions
449