1 // Copyright (c) 2018 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 // Unit tests for the TTS Controller.
6 
7 #include "content/browser/speech/tts_controller_impl.h"
8 
9 #include "base/memory/ptr_util.h"
10 #include "base/values.h"
11 #include "content/browser/speech/tts_utterance_impl.h"
12 #include "content/public/browser/tts_platform.h"
13 #include "content/public/browser/visibility.h"
14 #include "content/public/test/browser_task_environment.h"
15 #include "content/public/test/test_browser_context.h"
16 #include "content/public/test/test_renderer_host.h"
17 #include "content/test/test_content_browser_client.h"
18 #include "content/test/test_web_contents.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "third_party/blink/public/mojom/speech/speech_synthesis.mojom.h"
21 
22 #if defined(OS_CHROMEOS)
23 #include "content/public/browser/tts_controller_delegate.h"
24 #endif
25 
26 namespace content {
27 
28 // Platform Tts implementation that does nothing.
29 class MockTtsPlatformImpl : public TtsPlatform {
30  public:
MockTtsPlatformImpl(TtsController * controller)31   explicit MockTtsPlatformImpl(TtsController* controller)
32       : controller_(controller) {}
33   virtual ~MockTtsPlatformImpl() = default;
34 
35   // Override the Mock API results.
set_voices(const std::vector<VoiceData> & voices)36   void set_voices(const std::vector<VoiceData>& voices) { voices_ = voices; }
set_is_speaking(bool value)37   void set_is_speaking(bool value) { is_speaking_ = value; }
38 
39   // TtsPlatform:
PlatformImplSupported()40   bool PlatformImplSupported() override { return platform_supported_; }
PlatformImplInitialized()41   bool PlatformImplInitialized() override { return platform_initialized_; }
42 
Speak(int utterance_id,const std::string & utterance,const std::string & lang,const VoiceData & voice,const UtteranceContinuousParameters & params,base::OnceCallback<void (bool)> did_start_speaking_callback)43   void Speak(
44       int utterance_id,
45       const std::string& utterance,
46       const std::string& lang,
47       const VoiceData& voice,
48       const UtteranceContinuousParameters& params,
49       base::OnceCallback<void(bool)> did_start_speaking_callback) override {
50     utterance_id_ = utterance_id;
51     did_start_speaking_callback_ = std::move(did_start_speaking_callback);
52   }
IsSpeaking()53   bool IsSpeaking() override { return is_speaking_; }
StopSpeaking()54   bool StopSpeaking() override {
55     ++stop_speaking_called_;
56     return true;
57   }
Pause()58   void Pause() override { ++pause_called_; }
Resume()59   void Resume() override { ++resume_called_; }
GetVoices(std::vector<VoiceData> * out_voices)60   void GetVoices(std::vector<VoiceData>* out_voices) override {
61     *out_voices = voices_;
62   }
LoadBuiltInTtsEngine(BrowserContext * browser_context)63   bool LoadBuiltInTtsEngine(BrowserContext* browser_context) override {
64     return false;
65   }
WillSpeakUtteranceWithVoice(TtsUtterance * utterance,const VoiceData & voice_data)66   void WillSpeakUtteranceWithVoice(TtsUtterance* utterance,
67                                    const VoiceData& voice_data) override {}
SetError(const std::string & error)68   void SetError(const std::string& error) override { error_ = error; }
GetError()69   std::string GetError() override { return error_; }
ClearError()70   void ClearError() override { error_.clear(); }
Shutdown()71   void Shutdown() override {}
72 
SetPlatformImplSupported(bool state)73   void SetPlatformImplSupported(bool state) { platform_supported_ = state; }
SetPlatformImplInitialized(bool state)74   void SetPlatformImplInitialized(bool state) { platform_initialized_ = state; }
75 
76   // Returns the amount of calls to Mock API.
pause_called() const77   int pause_called() const { return pause_called_; }
resume_called() const78   int resume_called() const { return resume_called_; }
stop_speaking_called() const79   int stop_speaking_called() const { return stop_speaking_called_; }
80 
81   // Simulate the TTS platform calling back the closure
82   // |did_start_speaking_callback| passed to Speak(...). This closure can be
83   // called synchronously or asynchronously.
StartSpeaking(bool result)84   void StartSpeaking(bool result) {
85     is_speaking_ = true;
86     std::move(did_start_speaking_callback_).Run(result);
87   }
88 
FinishSpeaking()89   void FinishSpeaking() {
90     is_speaking_ = false;
91     controller_->OnTtsEvent(utterance_id_, TTS_EVENT_END, 0, 0, {});
92     utterance_id_ = -1;
93   }
94 
95  private:
96   TtsController* const controller_;
97   bool platform_supported_ = true;
98   bool platform_initialized_ = true;
99   std::vector<VoiceData> voices_;
100   int utterance_id_ = -1;
101   bool is_speaking_ = false;
102   int pause_called_ = 0;
103   int resume_called_ = 0;
104   int stop_speaking_called_ = 0;
105   std::string error_;
106   base::OnceCallback<void(bool)> did_start_speaking_callback_;
107 };
108 
109 #if defined(OS_CHROMEOS)
110 class MockTtsControllerDelegate : public TtsControllerDelegate {
111  public:
112   MockTtsControllerDelegate() = default;
113   ~MockTtsControllerDelegate() override = default;
114 
SetPreferredVoiceIds(const PreferredVoiceIds & ids)115   void SetPreferredVoiceIds(const PreferredVoiceIds& ids) { ids_ = ids; }
116 
GetLastBrowserContext()117   BrowserContext* GetLastBrowserContext() {
118     BrowserContext* result = last_browser_context_;
119     last_browser_context_ = nullptr;
120     return result;
121   }
122 
123   // TtsControllerDelegate:
GetPreferredVoiceIdsForUtterance(TtsUtterance * utterance)124   std::unique_ptr<PreferredVoiceIds> GetPreferredVoiceIdsForUtterance(
125       TtsUtterance* utterance) override {
126     last_browser_context_ = utterance->GetBrowserContext();
127     auto ids = std::make_unique<PreferredVoiceIds>(ids_);
128     return ids;
129   }
130 
UpdateUtteranceDefaultsFromPrefs(content::TtsUtterance * utterance,double * rate,double * pitch,double * volume)131   void UpdateUtteranceDefaultsFromPrefs(content::TtsUtterance* utterance,
132                                         double* rate,
133                                         double* pitch,
134                                         double* volume) override {}
135 
136  private:
137   BrowserContext* last_browser_context_ = nullptr;
138   PreferredVoiceIds ids_;
139 };
140 #endif
141 
142 class MockVoicesChangedDelegate : public VoicesChangedDelegate {
143  public:
OnVoicesChanged()144   void OnVoicesChanged() override {}
145 };
146 
147 class TestTtsControllerImpl : public TtsControllerImpl {
148  public:
149   TestTtsControllerImpl() = default;
150   ~TestTtsControllerImpl() override = default;
151 
152   // Exposed API for testing.
153   using TtsControllerImpl::FinishCurrentUtterance;
154   using TtsControllerImpl::GetMatchingVoice;
155   using TtsControllerImpl::SpeakNextUtterance;
156   using TtsControllerImpl::UpdateUtteranceDefaults;
157 #if defined(OS_CHROMEOS)
158   using TtsControllerImpl::SetTtsControllerDelegateForTesting;
159 #endif
160   using TtsControllerImpl::IsPausedForTesting;
161 
current_utterance()162   TtsUtterance* current_utterance() { return current_utterance_.get(); }
163 };
164 
165 class TtsControllerTest : public testing::Test {
166  public:
167   TtsControllerTest() = default;
168   ~TtsControllerTest() override = default;
169 
SetUp()170   void SetUp() override {
171     controller_ = std::make_unique<TestTtsControllerImpl>();
172     platform_impl_ = std::make_unique<MockTtsPlatformImpl>(controller_.get());
173     browser_context_ = std::make_unique<TestBrowserContext>();
174     controller()->SetTtsPlatform(platform_impl_.get());
175 #if defined(OS_CHROMEOS)
176     controller()->SetTtsControllerDelegateForTesting(&delegate_);
177 #endif
178     controller()->AddVoicesChangedDelegate(&voices_changed_);
179   }
180 
TearDown()181   void TearDown() override {
182     if (controller())
183       controller()->RemoveVoicesChangedDelegate(&voices_changed_);
184   }
185 
platform_impl()186   MockTtsPlatformImpl* platform_impl() { return platform_impl_.get(); }
controller()187   TestTtsControllerImpl* controller() { return controller_.get(); }
browser_context()188   TestBrowserContext* browser_context() { return browser_context_.get(); }
189 
190 #if defined(OS_CHROMEOS)
delegate()191   MockTtsControllerDelegate* delegate() { return &delegate_; }
192 #endif
193 
ReleaseTtsController()194   void ReleaseTtsController() { controller_.reset(); }
ReleaseBrowserContext()195   void ReleaseBrowserContext() {
196     // BrowserContext::~BrowserContext(...) is calling OnBrowserContextDestroyed
197     // on the tts controller singleton. That call is simulated here to ensures
198     // it is called on our test controller instances.
199     controller()->OnBrowserContextDestroyed(browser_context_.get());
200     browser_context_.reset();
201   }
202 
CreateWebContents()203   std::unique_ptr<TestWebContents> CreateWebContents() {
204     return std::unique_ptr<TestWebContents>(
205         TestWebContents::Create(browser_context_.get(), nullptr));
206   }
207 
CreateUtteranceImpl(WebContents * web_contents=nullptr)208   std::unique_ptr<TtsUtteranceImpl> CreateUtteranceImpl(
209       WebContents* web_contents = nullptr) {
210     return std::make_unique<TtsUtteranceImpl>(browser_context_.get(),
211                                               web_contents);
212   }
213 
TtsControllerCurrentUtterance()214   TtsUtterance* TtsControllerCurrentUtterance() {
215     return controller()->current_utterance();
216   }
217 
IsUtteranceListEmpty()218   bool IsUtteranceListEmpty() { return controller()->QueueSize() == 0; }
219 
220  private:
221   content::BrowserTaskEnvironment task_environment_;
222   RenderViewHostTestEnabler rvh_enabler_;
223 
224   std::unique_ptr<TestTtsControllerImpl> controller_;
225   std::unique_ptr<MockTtsPlatformImpl> platform_impl_;
226   std::unique_ptr<TestBrowserContext> browser_context_;
227 #if defined(OS_CHROMEOS)
228   MockTtsControllerDelegate delegate_;
229 #endif
230   MockVoicesChangedDelegate voices_changed_;
231 };
232 
TEST_F(TtsControllerTest,TestTtsControllerShutdown)233 TEST_F(TtsControllerTest, TestTtsControllerShutdown) {
234   std::unique_ptr<TtsUtterance> utterance1 = TtsUtterance::Create(nullptr);
235   utterance1->SetCanEnqueue(true);
236   utterance1->SetSrcId(1);
237   controller()->SpeakOrEnqueue(std::move(utterance1));
238 
239   std::unique_ptr<TtsUtterance> utterance2 = TtsUtterance::Create(nullptr);
240   utterance2->SetCanEnqueue(true);
241   utterance2->SetSrcId(2);
242   controller()->SpeakOrEnqueue(std::move(utterance2));
243 
244   // Make sure that deleting the controller when there are pending
245   // utterances doesn't cause a crash.
246   ReleaseTtsController();
247 }
248 
249 #if defined(OS_CHROMEOS)
TEST_F(TtsControllerTest,TestBrowserContextRemoved)250 TEST_F(TtsControllerTest, TestBrowserContextRemoved) {
251   std::vector<VoiceData> voices;
252   VoiceData voice_data;
253   voice_data.engine_id = "x";
254   voice_data.events.insert(TTS_EVENT_END);
255   voices.push_back(voice_data);
256   platform_impl()->set_voices(voices);
257 
258   // Speak an utterances associated with this test browser context.
259   std::unique_ptr<TtsUtterance> utterance1 =
260       TtsUtterance::Create(browser_context());
261   utterance1->SetEngineId("x");
262   utterance1->SetCanEnqueue(true);
263   utterance1->SetSrcId(1);
264   controller()->SpeakOrEnqueue(std::move(utterance1));
265 
266   // Assert that the delegate was called and it got our browser context.
267   ASSERT_EQ(browser_context(), delegate()->GetLastBrowserContext());
268 
269   // Now queue up a second utterance to be spoken, also associated with
270   // this browser context.
271   std::unique_ptr<TtsUtterance> utterance2 =
272       TtsUtterance::Create(browser_context());
273   utterance2->SetEngineId("x");
274   utterance2->SetCanEnqueue(true);
275   utterance2->SetSrcId(2);
276   controller()->SpeakOrEnqueue(std::move(utterance2));
277 
278   // Destroy the browser context before the utterance is spoken.
279   ReleaseBrowserContext();
280 
281   // Now speak the next utterance, and ensure that we don't get the
282   // destroyed browser context.
283   controller()->FinishCurrentUtterance();
284   controller()->SpeakNextUtterance();
285   ASSERT_EQ(nullptr, delegate()->GetLastBrowserContext());
286 }
287 #else
TEST_F(TtsControllerTest,TestTtsControllerUtteranceDefaults)288 TEST_F(TtsControllerTest, TestTtsControllerUtteranceDefaults) {
289   std::unique_ptr<TtsUtterance> utterance1 =
290       content::TtsUtterance::Create(nullptr);
291   // Initialized to default (unset constant) values.
292   EXPECT_EQ(blink::mojom::kSpeechSynthesisDoublePrefNotSet,
293             utterance1->GetContinuousParameters().rate);
294   EXPECT_EQ(blink::mojom::kSpeechSynthesisDoublePrefNotSet,
295             utterance1->GetContinuousParameters().pitch);
296   EXPECT_EQ(blink::mojom::kSpeechSynthesisDoublePrefNotSet,
297             utterance1->GetContinuousParameters().volume);
298 
299   controller()->UpdateUtteranceDefaults(utterance1.get());
300   // Updated to global defaults.
301   EXPECT_EQ(blink::mojom::kSpeechSynthesisDefaultRate,
302             utterance1->GetContinuousParameters().rate);
303   EXPECT_EQ(blink::mojom::kSpeechSynthesisDefaultPitch,
304             utterance1->GetContinuousParameters().pitch);
305   EXPECT_EQ(blink::mojom::kSpeechSynthesisDefaultVolume,
306             utterance1->GetContinuousParameters().volume);
307 }
308 #endif
309 
TEST_F(TtsControllerTest,TestGetMatchingVoice)310 TEST_F(TtsControllerTest, TestGetMatchingVoice) {
311   TestContentBrowserClient::GetInstance()->set_application_locale("en");
312 
313   {
314     // Calling GetMatchingVoice with no voices returns -1.
315     std::unique_ptr<TtsUtterance> utterance(TtsUtterance::Create(nullptr));
316     std::vector<VoiceData> voices;
317     EXPECT_EQ(-1, controller()->GetMatchingVoice(utterance.get(), voices));
318   }
319 
320   {
321     // Calling GetMatchingVoice with any voices returns the first one
322     // even if there are no criteria that match.
323     std::unique_ptr<TtsUtterance> utterance(TtsUtterance::Create(nullptr));
324     std::vector<VoiceData> voices(2);
325     EXPECT_EQ(0, controller()->GetMatchingVoice(utterance.get(), voices));
326   }
327 
328   {
329     // If nothing else matches, the English voice is returned.
330     // (In tests the language will always be English.)
331     std::unique_ptr<TtsUtterance> utterance(TtsUtterance::Create(nullptr));
332     std::vector<VoiceData> voices;
333     VoiceData fr_voice;
334     fr_voice.lang = "fr";
335     voices.push_back(fr_voice);
336     VoiceData en_voice;
337     en_voice.lang = "en";
338     voices.push_back(en_voice);
339     VoiceData de_voice;
340     de_voice.lang = "de";
341     voices.push_back(de_voice);
342     EXPECT_EQ(1, controller()->GetMatchingVoice(utterance.get(), voices));
343   }
344 
345   {
346     // Check precedence of various matching criteria.
347     std::vector<VoiceData> voices;
348     VoiceData voice0;
349     voices.push_back(voice0);
350     VoiceData voice1;
351     voice1.events.insert(TTS_EVENT_WORD);
352     voices.push_back(voice1);
353     VoiceData voice2;
354     voice2.lang = "de-DE";
355     voices.push_back(voice2);
356     VoiceData voice3;
357     voice3.lang = "fr-CA";
358     voices.push_back(voice3);
359     VoiceData voice4;
360     voice4.name = "Voice4";
361     voices.push_back(voice4);
362     VoiceData voice5;
363     voice5.engine_id = "id5";
364     voices.push_back(voice5);
365     VoiceData voice6;
366     voice6.engine_id = "id7";
367     voice6.name = "Voice6";
368     voice6.lang = "es-es";
369     voices.push_back(voice6);
370     VoiceData voice7;
371     voice7.engine_id = "id7";
372     voice7.name = "Voice7";
373     voice7.lang = "es-mx";
374     voices.push_back(voice7);
375     VoiceData voice8;
376     voice8.engine_id = "";
377     voice8.name = "Android";
378     voice8.lang = "";
379     voice8.native = true;
380     voices.push_back(voice8);
381 
382     std::unique_ptr<TtsUtterance> utterance(TtsUtterance::Create(nullptr));
383     EXPECT_EQ(0, controller()->GetMatchingVoice(utterance.get(), voices));
384 
385     std::set<TtsEventType> types;
386     types.insert(TTS_EVENT_WORD);
387     utterance->SetRequiredEventTypes(types);
388     EXPECT_EQ(1, controller()->GetMatchingVoice(utterance.get(), voices));
389 
390     utterance->SetLang("de-DE");
391     EXPECT_EQ(2, controller()->GetMatchingVoice(utterance.get(), voices));
392 
393     utterance->SetLang("fr-FR");
394     EXPECT_EQ(3, controller()->GetMatchingVoice(utterance.get(), voices));
395 
396     utterance->SetVoiceName("Voice4");
397     EXPECT_EQ(4, controller()->GetMatchingVoice(utterance.get(), voices));
398 
399     utterance->SetVoiceName("");
400     utterance->SetEngineId("id5");
401     EXPECT_EQ(5, controller()->GetMatchingVoice(utterance.get(), voices));
402 
403 #if defined(OS_CHROMEOS)
404     TtsControllerDelegate::PreferredVoiceIds preferred_voice_ids;
405     preferred_voice_ids.locale_voice_id.emplace("Voice7", "id7");
406     preferred_voice_ids.any_locale_voice_id.emplace("Android", "");
407     delegate()->SetPreferredVoiceIds(preferred_voice_ids);
408 
409     // Voice6 is matched when the utterance locale exactly matches its locale.
410     utterance->SetEngineId("");
411     utterance->SetLang("es-es");
412     EXPECT_EQ(6, controller()->GetMatchingVoice(utterance.get(), voices));
413 
414     // The 7th voice is the default for "es", even though the utterance is
415     // "es-ar". |voice6| is not matched because it is not the default.
416     utterance->SetEngineId("");
417     utterance->SetLang("es-ar");
418     EXPECT_EQ(7, controller()->GetMatchingVoice(utterance.get(), voices));
419 
420     // The 8th voice is like the built-in "Android" voice, it has no lang
421     // and no extension ID. Make sure it can still be matched.
422     preferred_voice_ids.locale_voice_id.reset();
423     delegate()->SetPreferredVoiceIds(preferred_voice_ids);
424     utterance->SetVoiceName("Android");
425     utterance->SetEngineId("");
426     utterance->SetLang("");
427     EXPECT_EQ(8, controller()->GetMatchingVoice(utterance.get(), voices));
428 
429     delegate()->SetPreferredVoiceIds({});
430 #endif
431   }
432 
433   {
434     // Check voices against system language.
435     std::vector<VoiceData> voices;
436     VoiceData voice0;
437     voice0.engine_id = "id0";
438     voice0.name = "voice0";
439     voice0.lang = "en-GB";
440     voices.push_back(voice0);
441     VoiceData voice1;
442     voice1.engine_id = "id1";
443     voice1.name = "voice1";
444     voice1.lang = "en-US";
445     voices.push_back(voice1);
446     std::unique_ptr<TtsUtterance> utterance(TtsUtterance::Create(nullptr));
447 
448     // voice1 is matched against the exact default system language.
449     TestContentBrowserClient::GetInstance()->set_application_locale("en-US");
450     utterance->SetLang("");
451     EXPECT_EQ(1, controller()->GetMatchingVoice(utterance.get(), voices));
452 
453 #if defined(OS_CHROMEOS)
454     // voice0 is matched against the system language which has no region piece.
455     TestContentBrowserClient::GetInstance()->set_application_locale("en");
456     EXPECT_EQ(0, controller()->GetMatchingVoice(utterance.get(), voices));
457 
458     TtsControllerDelegate::PreferredVoiceIds preferred_voice_ids2;
459     preferred_voice_ids2.locale_voice_id.emplace("voice0", "id0");
460     delegate()->SetPreferredVoiceIds(preferred_voice_ids2);
461     // voice0 is matched against the pref over the system language.
462     TestContentBrowserClient::GetInstance()->set_application_locale("en-US");
463     EXPECT_EQ(0, controller()->GetMatchingVoice(utterance.get(), voices));
464 #endif
465   }
466 }
467 
TEST_F(TtsControllerTest,StopsWhenWebContentsDestroyed)468 TEST_F(TtsControllerTest, StopsWhenWebContentsDestroyed) {
469   std::unique_ptr<WebContents> web_contents = CreateWebContents();
470   std::unique_ptr<TtsUtteranceImpl> utterance =
471       CreateUtteranceImpl(web_contents.get());
472 
473   controller()->SpeakOrEnqueue(std::move(utterance));
474   EXPECT_TRUE(controller()->IsSpeaking());
475   EXPECT_TRUE(TtsControllerCurrentUtterance());
476 
477   web_contents.reset();
478   // Destroying the WebContents should reset
479   // |TtsController::current_utterance_|.
480   EXPECT_FALSE(TtsControllerCurrentUtterance());
481 }
482 
TEST_F(TtsControllerTest,StartsQueuedUtteranceWhenWebContentsDestroyed)483 TEST_F(TtsControllerTest, StartsQueuedUtteranceWhenWebContentsDestroyed) {
484   std::unique_ptr<WebContents> web_contents1 = CreateWebContents();
485   std::unique_ptr<WebContents> web_contents2 = CreateWebContents();
486   std::unique_ptr<TtsUtteranceImpl> utterance1 =
487       CreateUtteranceImpl(web_contents1.get());
488   void* raw_utterance1 = utterance1.get();
489   std::unique_ptr<TtsUtteranceImpl> utterance2 =
490       CreateUtteranceImpl(web_contents2.get());
491   utterance2->SetCanEnqueue(true);
492   void* raw_utterance2 = utterance2.get();
493 
494   controller()->SpeakOrEnqueue(std::move(utterance1));
495   EXPECT_TRUE(controller()->IsSpeaking());
496   EXPECT_TRUE(TtsControllerCurrentUtterance());
497   controller()->SpeakOrEnqueue(std::move(utterance2));
498   EXPECT_EQ(raw_utterance1, TtsControllerCurrentUtterance());
499 
500   web_contents1.reset();
501   // Destroying |web_contents1| should delete |utterance1| and start
502   // |utterance2|.
503   EXPECT_TRUE(TtsControllerCurrentUtterance());
504   EXPECT_EQ(raw_utterance2, TtsControllerCurrentUtterance());
505 }
506 
TEST_F(TtsControllerTest,StartsQueuedUtteranceWhenWebContentsDestroyed2)507 TEST_F(TtsControllerTest, StartsQueuedUtteranceWhenWebContentsDestroyed2) {
508   std::unique_ptr<WebContents> web_contents1 = CreateWebContents();
509   std::unique_ptr<WebContents> web_contents2 = CreateWebContents();
510   std::unique_ptr<TtsUtteranceImpl> utterance1 =
511       CreateUtteranceImpl(web_contents1.get());
512   void* raw_utterance1 = utterance1.get();
513   std::unique_ptr<TtsUtteranceImpl> utterance2 =
514       CreateUtteranceImpl(web_contents1.get());
515   std::unique_ptr<TtsUtteranceImpl> utterance3 =
516       CreateUtteranceImpl(web_contents2.get());
517   void* raw_utterance3 = utterance3.get();
518   utterance2->SetCanEnqueue(true);
519   utterance3->SetCanEnqueue(true);
520 
521   controller()->SpeakOrEnqueue(std::move(utterance1));
522   controller()->SpeakOrEnqueue(std::move(utterance2));
523   controller()->SpeakOrEnqueue(std::move(utterance3));
524   EXPECT_TRUE(controller()->IsSpeaking());
525   EXPECT_EQ(raw_utterance1, TtsControllerCurrentUtterance());
526 
527   web_contents1.reset();
528   // Deleting |web_contents1| should delete |utterance1| and |utterance2| as
529   // they are both from |web_contents1|. |raw_utterance3| should be made the
530   // current as it's from a different WebContents.
531   EXPECT_EQ(raw_utterance3, TtsControllerCurrentUtterance());
532   EXPECT_TRUE(IsUtteranceListEmpty());
533 
534   web_contents2.reset();
535   // Deleting |web_contents2| should delete |utterance3| as it's from a
536   // different WebContents.
537   EXPECT_EQ(nullptr, TtsControllerCurrentUtterance());
538 }
539 
TEST_F(TtsControllerTest,StartsUtteranceWhenWebContentsHidden)540 TEST_F(TtsControllerTest, StartsUtteranceWhenWebContentsHidden) {
541   std::unique_ptr<TestWebContents> web_contents = CreateWebContents();
542   web_contents->SetVisibilityAndNotifyObservers(Visibility::HIDDEN);
543   std::unique_ptr<TtsUtteranceImpl> utterance =
544       CreateUtteranceImpl(web_contents.get());
545   controller()->SpeakOrEnqueue(std::move(utterance));
546   EXPECT_TRUE(controller()->IsSpeaking());
547 }
548 
TEST_F(TtsControllerTest,DoesNotStartUtteranceWhenWebContentsHiddenAndStopSpeakingWhenHiddenSet)549 TEST_F(TtsControllerTest,
550        DoesNotStartUtteranceWhenWebContentsHiddenAndStopSpeakingWhenHiddenSet) {
551   std::unique_ptr<TestWebContents> web_contents = CreateWebContents();
552   web_contents->SetVisibilityAndNotifyObservers(Visibility::HIDDEN);
553   std::unique_ptr<TtsUtteranceImpl> utterance =
554       CreateUtteranceImpl(web_contents.get());
555   controller()->SetStopSpeakingWhenHidden(true);
556   controller()->SpeakOrEnqueue(std::move(utterance));
557   EXPECT_EQ(nullptr, TtsControllerCurrentUtterance());
558   EXPECT_TRUE(IsUtteranceListEmpty());
559 }
560 
TEST_F(TtsControllerTest,SkipsQueuedUtteranceFromHiddenWebContents)561 TEST_F(TtsControllerTest, SkipsQueuedUtteranceFromHiddenWebContents) {
562   controller()->SetStopSpeakingWhenHidden(true);
563   std::unique_ptr<WebContents> web_contents1 = CreateWebContents();
564   std::unique_ptr<TestWebContents> web_contents2 = CreateWebContents();
565   std::unique_ptr<TtsUtteranceImpl> utterance1 =
566       CreateUtteranceImpl(web_contents1.get());
567   const int utterance1_id = utterance1->GetId();
568   std::unique_ptr<TtsUtteranceImpl> utterance2 =
569       CreateUtteranceImpl(web_contents2.get());
570   utterance2->SetCanEnqueue(true);
571 
572   controller()->SpeakOrEnqueue(std::move(utterance1));
573   EXPECT_TRUE(TtsControllerCurrentUtterance());
574   EXPECT_TRUE(IsUtteranceListEmpty());
575 
576   // Speak |utterance2|, which should get queued.
577   controller()->SpeakOrEnqueue(std::move(utterance2));
578   EXPECT_FALSE(IsUtteranceListEmpty());
579 
580   // Make the second WebContents hidden, this shouldn't change anything in
581   // TtsController.
582   web_contents2->SetVisibilityAndNotifyObservers(Visibility::HIDDEN);
583   EXPECT_FALSE(IsUtteranceListEmpty());
584 
585   // Finish |utterance1|, which should skip |utterance2| because |web_contents2|
586   // is hidden.
587   controller()->OnTtsEvent(utterance1_id, TTS_EVENT_END, 0, 0, {});
588   EXPECT_EQ(nullptr, TtsControllerCurrentUtterance());
589   EXPECT_TRUE(IsUtteranceListEmpty());
590 }
591 
TEST_F(TtsControllerTest,PauseResumeNoUtterance)592 TEST_F(TtsControllerTest, PauseResumeNoUtterance) {
593   // Pause should not call the platform API when there is no utterance.
594   controller()->Pause();
595   controller()->Resume();
596   EXPECT_EQ(0, platform_impl()->pause_called());
597   EXPECT_EQ(0, platform_impl()->resume_called());
598 }
599 
TEST_F(TtsControllerTest,SpeakPauseResume)600 TEST_F(TtsControllerTest, SpeakPauseResume) {
601   std::unique_ptr<WebContents> web_contents = CreateWebContents();
602   std::unique_ptr<TtsUtteranceImpl> utterance =
603       CreateUtteranceImpl(web_contents.get());
604   utterance->SetCanEnqueue(true);
605 
606   // Start speaking an utterance.
607   controller()->SpeakOrEnqueue(std::move(utterance));
608   platform_impl()->StartSpeaking(true);
609 
610   // Pause the currently playing utterance should call the platform API pause.
611   controller()->Pause();
612   EXPECT_TRUE(controller()->IsPausedForTesting());
613   EXPECT_EQ(1, platform_impl()->pause_called());
614 
615   // Double pause should not call again the platform API pause.
616   controller()->Pause();
617   EXPECT_EQ(1, platform_impl()->pause_called());
618 
619   EXPECT_TRUE(IsUtteranceListEmpty());
620   EXPECT_TRUE(TtsControllerCurrentUtterance());
621 
622   // Resuming the playing utterance should call the platform API resume.
623   controller()->Resume();
624   EXPECT_FALSE(controller()->IsPausedForTesting());
625   EXPECT_EQ(1, platform_impl()->resume_called());
626 
627   // Double resume should not call again the platform API resume.
628   controller()->Resume();
629   EXPECT_EQ(1, platform_impl()->resume_called());
630   EXPECT_TRUE(controller()->IsSpeaking());
631 
632   // Complete the playing utterance.
633   platform_impl()->FinishSpeaking();
634 
635   EXPECT_TRUE(IsUtteranceListEmpty());
636   EXPECT_FALSE(TtsControllerCurrentUtterance());
637   EXPECT_FALSE(controller()->IsSpeaking());
638 }
639 
TEST_F(TtsControllerTest,SpeakWhenPaused)640 TEST_F(TtsControllerTest, SpeakWhenPaused) {
641   std::unique_ptr<WebContents> web_contents = CreateWebContents();
642   std::unique_ptr<TtsUtteranceImpl> utterance =
643       CreateUtteranceImpl(web_contents.get());
644   utterance->SetCanEnqueue(true);
645 
646   // Pause the controller.
647   controller()->Pause();
648   EXPECT_TRUE(controller()->IsPausedForTesting());
649 
650   // Speak an utterance while controller is paused, the utterance should be
651   // queued.
652   controller()->SpeakOrEnqueue(std::move(utterance));
653   EXPECT_FALSE(IsUtteranceListEmpty());
654   EXPECT_FALSE(TtsControllerCurrentUtterance());
655 
656   // Resume speaking, the utterance should start playing.
657   controller()->Resume();
658   EXPECT_FALSE(controller()->IsPausedForTesting());
659   EXPECT_TRUE(IsUtteranceListEmpty());
660   EXPECT_TRUE(TtsControllerCurrentUtterance());
661 
662   // Simulate platform starting to play the utterance.
663   platform_impl()->StartSpeaking(true);
664   EXPECT_TRUE(IsUtteranceListEmpty());
665   EXPECT_TRUE(TtsControllerCurrentUtterance());
666 
667   EXPECT_TRUE(controller()->IsSpeaking());
668 
669   // Complete the playing utterance.
670   platform_impl()->FinishSpeaking();
671   EXPECT_TRUE(IsUtteranceListEmpty());
672   EXPECT_FALSE(TtsControllerCurrentUtterance());
673   EXPECT_FALSE(controller()->IsSpeaking());
674 }
675 
TEST_F(TtsControllerTest,SpeakWhenPausedAndCannotEnqueueUtterance)676 TEST_F(TtsControllerTest, SpeakWhenPausedAndCannotEnqueueUtterance) {
677   std::unique_ptr<WebContents> web_contents = CreateWebContents();
678   std::unique_ptr<TtsUtteranceImpl> utterance1 =
679       CreateUtteranceImpl(web_contents.get());
680   utterance1->SetCanEnqueue(false);
681 
682   // Pause the controller.
683   controller()->Pause();
684   EXPECT_TRUE(controller()->IsPausedForTesting());
685 
686   // Speak an utterance while controller is paused. The utterance cannot be
687   // queued and should be dropped.
688   controller()->SpeakOrEnqueue(std::move(utterance1));
689   EXPECT_TRUE(IsUtteranceListEmpty());
690   EXPECT_FALSE(TtsControllerCurrentUtterance());
691 
692   // Speak an utterance that can be queued. The controller should stay paused
693   // and the second utterance must be queued.
694   std::unique_ptr<TtsUtteranceImpl> utterance2 =
695       CreateUtteranceImpl(web_contents.get());
696   utterance2->SetCanEnqueue(true);
697 
698   controller()->SpeakOrEnqueue(std::move(utterance2));
699   EXPECT_TRUE(controller()->IsPausedForTesting());
700   EXPECT_FALSE(IsUtteranceListEmpty());
701   EXPECT_FALSE(TtsControllerCurrentUtterance());
702 
703   // Speak an utterance that cannot be queued should clear the queue.
704   std::unique_ptr<TtsUtteranceImpl> utterance3 =
705       CreateUtteranceImpl(web_contents.get());
706   utterance3->SetCanEnqueue(false);
707 
708   controller()->SpeakOrEnqueue(std::move(utterance3));
709   EXPECT_TRUE(controller()->IsPausedForTesting());
710   EXPECT_TRUE(IsUtteranceListEmpty());
711   EXPECT_FALSE(TtsControllerCurrentUtterance());
712 
713   // Resume the controller.
714   controller()->Resume();
715   EXPECT_FALSE(controller()->IsPausedForTesting());
716 }
717 
TEST_F(TtsControllerTest,StopMustResumeController)718 TEST_F(TtsControllerTest, StopMustResumeController) {
719   std::unique_ptr<WebContents> web_contents = CreateWebContents();
720   std::unique_ptr<TtsUtteranceImpl> utterance =
721       CreateUtteranceImpl(web_contents.get());
722   utterance->SetCanEnqueue(true);
723 
724   // Speak an utterance while controller is paused. The utterance is queued.
725   controller()->SpeakOrEnqueue(std::move(utterance));
726   platform_impl()->StartSpeaking(true);
727   EXPECT_TRUE(IsUtteranceListEmpty());
728   EXPECT_TRUE(TtsControllerCurrentUtterance());
729 
730   platform_impl()->SetError("dummy");
731 
732   // Stop must resume the controller and clear the current utterance.
733   controller()->Stop();
734   platform_impl()->FinishSpeaking();
735 
736   EXPECT_EQ(2, platform_impl()->stop_speaking_called());
737   EXPECT_TRUE(IsUtteranceListEmpty());
738   EXPECT_FALSE(TtsControllerCurrentUtterance());
739   EXPECT_TRUE(platform_impl()->GetError().empty());
740   EXPECT_FALSE(controller()->IsSpeaking());
741 }
742 
TEST_F(TtsControllerTest,PauseAndStopMustResumeController)743 TEST_F(TtsControllerTest, PauseAndStopMustResumeController) {
744   std::unique_ptr<WebContents> web_contents = CreateWebContents();
745   std::unique_ptr<TtsUtteranceImpl> utterance =
746       CreateUtteranceImpl(web_contents.get());
747   utterance->SetCanEnqueue(true);
748 
749   // Pause the controller.
750   controller()->Pause();
751   EXPECT_TRUE(controller()->IsPausedForTesting());
752 
753   // Speak an utterance while controller is paused. The utterance is queued.
754   controller()->SpeakOrEnqueue(std::move(utterance));
755   EXPECT_FALSE(IsUtteranceListEmpty());
756   EXPECT_FALSE(TtsControllerCurrentUtterance());
757 
758   platform_impl()->SetError("dummy");
759 
760   // Stop must resume the controller and clear the queue.
761   controller()->Stop();
762   EXPECT_FALSE(controller()->IsPausedForTesting());
763   EXPECT_EQ(1, platform_impl()->stop_speaking_called());
764   EXPECT_TRUE(IsUtteranceListEmpty());
765   EXPECT_FALSE(TtsControllerCurrentUtterance());
766   EXPECT_TRUE(platform_impl()->GetError().empty());
767 }
768 
TEST_F(TtsControllerTest,PlatformNotSupported)769 TEST_F(TtsControllerTest, PlatformNotSupported) {
770   std::unique_ptr<WebContents> web_contents = CreateWebContents();
771   std::unique_ptr<TtsUtteranceImpl> utterance =
772       CreateUtteranceImpl(web_contents.get());
773 
774   // The utterance is dropped when the platform is not available.
775   platform_impl()->SetPlatformImplSupported(false);
776   controller()->SpeakOrEnqueue(std::move(utterance));
777   EXPECT_FALSE(TtsControllerCurrentUtterance());
778   EXPECT_TRUE(IsUtteranceListEmpty());
779 
780   // No methods are called on the platform when not available.
781   controller()->Pause();
782   controller()->Resume();
783   controller()->Stop();
784 
785   EXPECT_EQ(0, platform_impl()->pause_called());
786   EXPECT_EQ(0, platform_impl()->resume_called());
787   EXPECT_EQ(0, platform_impl()->stop_speaking_called());
788 }
789 
TEST_F(TtsControllerTest,SpeakWhenLoading)790 TEST_F(TtsControllerTest, SpeakWhenLoading) {
791   platform_impl()->SetPlatformImplInitialized(false);
792 
793   std::unique_ptr<WebContents> web_contents = CreateWebContents();
794   std::unique_ptr<TtsUtteranceImpl> utterance =
795       CreateUtteranceImpl(web_contents.get());
796   utterance->SetCanEnqueue(true);
797 
798   // Speak an utterance while platform is loading, the utterance should be
799   // queued.
800   controller()->SpeakOrEnqueue(std::move(utterance));
801   EXPECT_FALSE(IsUtteranceListEmpty());
802   EXPECT_FALSE(TtsControllerCurrentUtterance());
803 
804   // Simulate the completion of the initialisation.
805   platform_impl()->SetPlatformImplInitialized(true);
806   controller()->VoicesChanged();
807 
808   platform_impl()->StartSpeaking(true);
809   EXPECT_TRUE(IsUtteranceListEmpty());
810   EXPECT_TRUE(TtsControllerCurrentUtterance());
811   EXPECT_TRUE(controller()->IsSpeaking());
812 
813   // Complete the playing utterance.
814   platform_impl()->FinishSpeaking();
815   EXPECT_TRUE(IsUtteranceListEmpty());
816   EXPECT_FALSE(TtsControllerCurrentUtterance());
817   EXPECT_FALSE(controller()->IsSpeaking());
818 }
819 
820 }  // namespace content
821