• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.speech.tts;
18 
19 import android.speech.tts.SynthesisCallback;
20 import android.speech.tts.SynthesisRequest;
21 import android.speech.tts.TextToSpeech;
22 import android.test.InstrumentationTestCase;
23 
24 import com.android.speech.tts.MockableTextToSpeechService.IDelegate;
25 import org.mockito.ArgumentCaptor;
26 import org.mockito.Mockito;
27 import org.mockito.internal.stubbing.StubberImpl;
28 import org.mockito.invocation.InvocationOnMock;
29 import org.mockito.stubbing.Answer;
30 import org.mockito.stubbing.Stubber;
31 import junit.framework.Assert;
32 
33 import java.util.Locale;
34 import java.util.concurrent.Callable;
35 import java.util.concurrent.CountDownLatch;
36 import java.util.concurrent.TimeUnit;
37 
38 public class TextToSpeechTests extends InstrumentationTestCase {
39     private static final String MOCK_ENGINE = "com.android.speech.tts";
40     private static final String MOCK_PACKAGE = "com.android.speech.tts.__testpackage__";
41 
42     private TextToSpeech mTts;
43 
44     @Override
setUp()45     public void setUp() throws Exception {
46         IDelegate passThrough = Mockito.mock(IDelegate.class);
47         MockableTextToSpeechService.setMocker(passThrough);
48 
49         // For the default voice selection
50         Mockito.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(passThrough)
51             .onIsLanguageAvailable(
52                     Mockito.anyString(), Mockito.anyString(), Mockito.anyString());
53         Mockito.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(passThrough)
54             .onLoadLanguage(
55                     Mockito.anyString(), Mockito.anyString(), Mockito.anyString());
56 
57         blockingInitAndVerify(MOCK_ENGINE, TextToSpeech.SUCCESS);
58         assertEquals(MOCK_ENGINE, mTts.getCurrentEngine());
59     }
60 
61     @Override
tearDown()62     public void tearDown() {
63         if (mTts != null) {
64             mTts.shutdown();
65         }
66     }
67 
testEngineInitialized()68     public void testEngineInitialized() throws Exception {
69         // Fail on an engine that doesn't exist.
70         blockingInitAndVerify("__DOES_NOT_EXIST__", TextToSpeech.ERROR);
71 
72         // Also, the "current engine" must be null
73         assertNull(mTts.getCurrentEngine());
74     }
75 
testSetLanguage_delegation()76     public void testSetLanguage_delegation() {
77         IDelegate delegate = Mockito.mock(IDelegate.class);
78         MockableTextToSpeechService.setMocker(delegate);
79 
80         Mockito.doReturn(TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE).when(delegate).onIsLanguageAvailable(
81                 "eng", "USA", "variant");
82         Mockito.doReturn(TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE).when(delegate).onLoadLanguage(
83                 "eng", "USA", "variant");
84 
85         // Test 1 :Tests that calls to onLoadLanguage( ) are delegated through to the
86         // service without any caching or intermediate steps.
87         assertEquals(TextToSpeech.LANG_COUNTRY_VAR_AVAILABLE, mTts.setLanguage(new Locale("eng", "USA", "variant")));
88         Mockito.verify(delegate, Mockito.atLeast(0)).onIsLanguageAvailable(
89             "eng", "USA", "variant");
90         Mockito.verify(delegate, Mockito.atLeast(0)).onLoadLanguage(
91             "eng", "USA", "variant");
92     }
93 
testSetLanguage_availableLanguage()94     public void testSetLanguage_availableLanguage() throws Exception {
95         IDelegate delegate = Mockito.mock(IDelegate.class);
96         MockableTextToSpeechService.setMocker(delegate);
97 
98         // ---------------------------------------------------------
99         // Test 2 : Tests that when the language is successfully set
100         // like above (returns LANG_COUNTRY_AVAILABLE). That the
101         // request language changes from that point on.
102         Mockito.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onIsLanguageAvailable(
103                 "eng", "USA", "variant");
104         Mockito.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onIsLanguageAvailable(
105                 "eng", "USA", "");
106         Mockito.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onLoadLanguage(
107                 "eng", "USA", "");
108         mTts.setLanguage(new Locale("eng", "USA", "variant"));
109         blockingCallSpeak("foo bar", delegate);
110         ArgumentCaptor<SynthesisRequest> req = ArgumentCaptor.forClass(SynthesisRequest.class);
111         Mockito.verify(delegate, Mockito.times(1)).onSynthesizeText(req.capture(),
112                 Mockito.<SynthesisCallback>anyObject());
113 
114         assertEquals("eng", req.getValue().getLanguage());
115         assertEquals("USA", req.getValue().getCountry());
116         assertEquals("", req.getValue().getVariant());
117         assertEquals("en-US", req.getValue().getVoiceName());
118     }
119 
testSetLanguage_unavailableLanguage()120     public void testSetLanguage_unavailableLanguage() throws Exception {
121         IDelegate delegate = Mockito.mock(IDelegate.class);
122         MockableTextToSpeechService.setMocker(delegate);
123 
124         // ---------------------------------------------------------
125         // TEST 3 : Tests that the language that is set does not change when the
126         // engine reports it could not load the specified language.
127         Mockito.doReturn(TextToSpeech.LANG_NOT_SUPPORTED).when(
128                 delegate).onIsLanguageAvailable("fra", "FRA", "");
129         Mockito.doReturn(TextToSpeech.LANG_NOT_SUPPORTED).when(
130                 delegate).onLoadLanguage("fra", "FRA", "");
131         mTts.setLanguage(Locale.FRANCE);
132         blockingCallSpeak("le fou barre", delegate);
133         ArgumentCaptor<SynthesisRequest> req2 = ArgumentCaptor.forClass(SynthesisRequest.class);
134         Mockito.verify(delegate, Mockito.times(1)).onSynthesizeText(req2.capture(),
135                         Mockito.<SynthesisCallback>anyObject());
136 
137         // The params are basically unchanged.
138         assertEquals("eng", req2.getValue().getLanguage());
139         assertEquals("USA", req2.getValue().getCountry());
140         assertEquals("", req2.getValue().getVariant());
141         assertEquals("en-US", req2.getValue().getVoiceName());
142     }
143 
testIsLanguageAvailable()144     public void testIsLanguageAvailable() {
145         IDelegate delegate = Mockito.mock(IDelegate.class);
146         MockableTextToSpeechService.setMocker(delegate);
147 
148         // Test1: Simple end to end test.
149         Mockito.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(
150                 delegate).onIsLanguageAvailable("eng", "USA", "");
151 
152         assertEquals(TextToSpeech.LANG_COUNTRY_AVAILABLE, mTts.isLanguageAvailable(Locale.US));
153         Mockito.verify(delegate, Mockito.times(1)).onIsLanguageAvailable(
154                 "eng", "USA", "");
155     }
156 
testDefaultLanguage_setsVoiceName()157     public void testDefaultLanguage_setsVoiceName() throws Exception {
158         IDelegate delegate = Mockito.mock(IDelegate.class);
159         MockableTextToSpeechService.setMocker(delegate);
160         Locale defaultLocale = Locale.getDefault();
161 
162         // ---------------------------------------------------------
163         // Test that default language also sets the default voice
164         // name
165         Mockito.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).
166             when(delegate).onIsLanguageAvailable(
167                 defaultLocale.getISO3Language(),
168                 defaultLocale.getISO3Country().toUpperCase(),
169                 defaultLocale.getVariant());
170         Mockito.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).
171             when(delegate).onLoadLanguage(
172                 defaultLocale.getISO3Language(),
173                 defaultLocale.getISO3Country(),
174                 defaultLocale.getVariant());
175 
176         blockingCallSpeak("foo bar", delegate);
177         ArgumentCaptor<SynthesisRequest> req = ArgumentCaptor.forClass(SynthesisRequest.class);
178         Mockito.verify(delegate, Mockito.times(1)).onSynthesizeText(req.capture(),
179                 Mockito.<SynthesisCallback>anyObject());
180 
181         assertEquals(defaultLocale.getISO3Language(), req.getValue().getLanguage());
182         assertEquals(defaultLocale.getISO3Country(), req.getValue().getCountry());
183         assertEquals("", req.getValue().getVariant());
184         assertEquals(defaultLocale.toLanguageTag(), req.getValue().getVoiceName());
185     }
186 
187 
blockingCallSpeak(String speech, IDelegate mock)188     private void blockingCallSpeak(String speech, IDelegate mock) throws
189             InterruptedException {
190         final CountDownLatch latch = new CountDownLatch(1);
191         doCountDown(latch).when(mock).onSynthesizeText(Mockito.<SynthesisRequest>anyObject(),
192                 Mockito.<SynthesisCallback>anyObject());
193         mTts.speak(speech, TextToSpeech.QUEUE_ADD, null);
194 
195         awaitCountDown(latch, 5, TimeUnit.SECONDS);
196     }
197 
blockingInitAndVerify(final String engine, int errorCode)198     private void blockingInitAndVerify(final String engine, int errorCode) throws
199             InterruptedException {
200         TextToSpeech.OnInitListener listener = Mockito.mock(
201                 TextToSpeech.OnInitListener.class);
202 
203         final CountDownLatch latch = new CountDownLatch(1);
204         doCountDown(latch).when(listener).onInit(errorCode);
205 
206         mTts = new TextToSpeech(getInstrumentation().getTargetContext(),
207                 listener, engine, MOCK_PACKAGE, false /* use fallback package */);
208 
209         awaitCountDown(latch, 5, TimeUnit.SECONDS);
210     }
211 
212     public static abstract class CountDownBehaviour extends StubberImpl {
213         /** Used to mock methods that return a result. */
andReturn(Object result)214         public abstract Stubber andReturn(Object result);
215     }
216 
doCountDown(final CountDownLatch latch)217     public static CountDownBehaviour doCountDown(final CountDownLatch latch) {
218         return new CountDownBehaviour() {
219             @Override
220             public <T> T when(T mock) {
221                 return Mockito.doAnswer(new Answer<Void>() {
222                     @Override
223                     public Void answer(InvocationOnMock invocation) throws Exception {
224                         latch.countDown();
225                         return null;
226                     }
227                 }).when(mock);
228             }
229 
230             @Override
231             public Stubber andReturn(final Object result) {
232                 return new StubberImpl() {
233                     @Override
234                     public <T> T when(T mock) {
235                         return Mockito.doAnswer(new Answer<Object>() {
236                             @Override
237                             public Object answer(InvocationOnMock invocation) throws Exception {
238                                 latch.countDown();
239                                 return result;
240                             }
241                         }).when(mock);
242                     }
243                 };
244             }
245         };
246     }
247 
248     public static void awaitCountDown(CountDownLatch latch, long timeout, TimeUnit unit)
249             throws InterruptedException {
250         Assert.assertTrue("Waited too long for method call", latch.await(timeout, unit));
251     }
252 }
253