diff options
author | Narayan Kamath <narayan@google.com> | 2012-01-11 03:39:57 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2012-01-11 03:39:57 -0800 |
commit | 81754949e0110b9db44bef421d6282a3bf831138 (patch) | |
tree | ccd21a4ae75fff20f744a6c51a165ac4e727da3e /tests | |
parent | 49a13f0052e93dc0b451a4c41bff9b2f8a0286e2 (diff) | |
parent | c60aad2a8ab519a9f9ac03f4f9f929ded7ba2db5 (diff) | |
download | frameworks_base-81754949e0110b9db44bef421d6282a3bf831138.zip frameworks_base-81754949e0110b9db44bef421d6282a3bf831138.tar.gz frameworks_base-81754949e0110b9db44bef421d6282a3bf831138.tar.bz2 |
Merge "Write unit tests for android.speech.tts."
Diffstat (limited to 'tests')
5 files changed, 436 insertions, 0 deletions
diff --git a/tests/TtsTests/Android.mk b/tests/TtsTests/Android.mk new file mode 100644 index 0000000..e049c90 --- /dev/null +++ b/tests/TtsTests/Android.mk @@ -0,0 +1,28 @@ +# +# Copyright (C) 2011 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_STATIC_JAVA_LIBRARIES := littlemock +LOCAL_JAVA_LIBRARIES := android.test.runner + +LOCAL_PACKAGE_NAME := TtsTests + +include $(BUILD_PACKAGE) diff --git a/tests/TtsTests/AndroidManifest.xml b/tests/TtsTests/AndroidManifest.xml new file mode 100644 index 0000000..b6d5111 --- /dev/null +++ b/tests/TtsTests/AndroidManifest.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +Copyright (C) 2011 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +--> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.speech.tts"> + <application> + <uses-library android:name="android.test.runner" /> + + + <service android:name=".MockableTextToSpeechService" + android:label="Mockable Text-to-speech Service"> + <intent-filter> + <action android:name="android.intent.action.TTS_SERVICE" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </service> + + <activity android:name=".MockableCheckVoiceData" + android:theme="@android:style/Theme.NoDisplay"> + <intent-filter> + <action android:name="android.speech.tts.engine.CHECK_TTS_DATA" /> + <category android:name="android.intent.category.DEFAULT" /> + </intent-filter> + </activity> + </application> + + <instrumentation android:name="android.test.InstrumentationTestRunner" + android:targetPackage="com.android.speech.tts" + android:label="Tests for android.speech.tts" /> +</manifest> diff --git a/tests/TtsTests/src/com/android/speech/tts/MockableCheckVoiceData.java b/tests/TtsTests/src/com/android/speech/tts/MockableCheckVoiceData.java new file mode 100644 index 0000000..0ab8ed6 --- /dev/null +++ b/tests/TtsTests/src/com/android/speech/tts/MockableCheckVoiceData.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.speech.tts; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.speech.tts.TextToSpeech; + +import java.util.ArrayList; +import java.util.List; + +public class MockableCheckVoiceData extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + MockableTextToSpeechService.IDelegate delegate = + MockableTextToSpeechService.getMocker(); + + ArrayList<String> availableLangs = delegate.getAvailableVoices(); + ArrayList<String> unavailableLangs = delegate.getUnavailableVoices(); + + final Intent returnVal = new Intent(); + + // Returns early. + if (availableLangs == null) { + setResult(TextToSpeech.Engine.CHECK_VOICE_DATA_FAIL, returnVal); + finish(); + return; + } + + returnVal.putStringArrayListExtra(TextToSpeech.Engine.EXTRA_AVAILABLE_VOICES, + availableLangs); + + if (unavailableLangs != null && unavailableLangs.size() > 0) { + returnVal.putStringArrayListExtra(TextToSpeech.Engine.EXTRA_UNAVAILABLE_VOICES, + unavailableLangs); + } + + setResult(TextToSpeech.Engine.CHECK_VOICE_DATA_PASS, returnVal); + finish(); + } + +} diff --git a/tests/TtsTests/src/com/android/speech/tts/MockableTextToSpeechService.java b/tests/TtsTests/src/com/android/speech/tts/MockableTextToSpeechService.java new file mode 100644 index 0000000..20648a4 --- /dev/null +++ b/tests/TtsTests/src/com/android/speech/tts/MockableTextToSpeechService.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.speech.tts; + +import android.speech.tts.SynthesisCallback; +import android.speech.tts.SynthesisRequest; +import android.speech.tts.TextToSpeechService; + +import java.util.ArrayList; + +public class MockableTextToSpeechService extends TextToSpeechService { + + private static IDelegate sDelegate; + + public static void setMocker(IDelegate delegate) { + sDelegate = delegate; + } + + static IDelegate getMocker() { + return sDelegate; + } + + @Override + protected int onIsLanguageAvailable(String lang, String country, String variant) { + return sDelegate.onIsLanguageAvailable(lang, country, variant); + } + + @Override + protected String[] onGetLanguage() { + return sDelegate.onGetLanguage(); + } + + @Override + protected int onLoadLanguage(String lang, String country, String variant) { + return sDelegate.onLoadLanguage(lang, country, variant); + } + + @Override + protected void onStop() { + sDelegate.onStop(); + } + + @Override + protected void onSynthesizeText(SynthesisRequest request, SynthesisCallback callback) { + sDelegate.onSynthesizeText(request, callback); + } + + public static interface IDelegate { + int onIsLanguageAvailable(String lang, String country, String variant); + + String[] onGetLanguage(); + + int onLoadLanguage(String lang, String country, String variant); + + void onStop(); + + void onSynthesizeText(SynthesisRequest request, SynthesisCallback callback); + + ArrayList<String> getAvailableVoices(); + + ArrayList<String> getUnavailableVoices(); + } + +} diff --git a/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java new file mode 100644 index 0000000..b736e9f --- /dev/null +++ b/tests/TtsTests/src/com/android/speech/tts/TextToSpeechTests.java @@ -0,0 +1,229 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.speech.tts; + +import android.speech.tts.SynthesisCallback; +import android.speech.tts.SynthesisRequest; +import android.speech.tts.TextToSpeech; +import android.test.InstrumentationTestCase; + +import com.android.speech.tts.MockableTextToSpeechService.IDelegate; +import com.google.testing.littlemock.ArgumentCaptor; +import com.google.testing.littlemock.Behaviour; +import com.google.testing.littlemock.LittleMock; +import junit.framework.Assert; + +import java.util.Locale; +import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +public class TextToSpeechTests extends InstrumentationTestCase { + private static final String MOCK_ENGINE = "com.android.speech.tts"; + private static final String MOCK_PACKAGE = "com.android.speech.tts.__testpackage__"; + + private TextToSpeech mTts; + + @Override + public void setUp() throws Exception { + IDelegate passThrough = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(passThrough); + + blockingInitAndVerify(MOCK_ENGINE, TextToSpeech.SUCCESS); + assertEquals(MOCK_ENGINE, mTts.getCurrentEngine()); + } + + + @Override + public void tearDown() { + if (mTts != null) { + mTts.shutdown(); + } + } + + public void testEngineInitialized() throws Exception { + // Fail on an engine that doesn't exist. + blockingInitAndVerify("__DOES_NOT_EXIST__", TextToSpeech.ERROR); + + // Also, the "current engine" must be null + assertNull(mTts.getCurrentEngine()); + } + + public void testSetLanguage_delegation() { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // Test 1 :Tests that calls to onLoadLanguage( ) are delegated through to the + // service without any caching or intermediate steps. + mTts.setLanguage(new Locale("eng", "USA", "variant")); + LittleMock.verify(delegate, LittleMock.times(1)).onLoadLanguage( + "eng", "USA", "variant"); + } + + public void testSetLanguage_availableLanguage() throws Exception { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // --------------------------------------------------------- + // Test 2 : Tests that when the language is successfully set + // like above (returns LANG_COUNTRY_AVAILABLE). That the + // request language changes from that point on. + LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when(delegate).onLoadLanguage( + "eng", "USA", "variant"); + mTts.setLanguage(new Locale("eng", "USA", "variant")); + blockingCallSpeak("foo bar", delegate); + ArgumentCaptor<SynthesisRequest> req = LittleMock.createCaptor(); + LittleMock.verify(delegate, LittleMock.times(1)).onSynthesizeText(req.capture(), + LittleMock.<SynthesisCallback>anyObject()); + + assertEquals("eng", req.getValue().getLanguage()); + assertEquals("USA", req.getValue().getCountry()); + assertEquals("", req.getValue().getVariant()); + } + + public void testSetLanguage_unavailableLanguage() throws Exception { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // --------------------------------------------------------- + // TEST 3 : Tests that the language that is set does not change when the + // engine reports it could not load the specified language. + LittleMock.doReturn(TextToSpeech.LANG_NOT_SUPPORTED).when( + delegate).onLoadLanguage("fra", "FRA", ""); + mTts.setLanguage(Locale.FRANCE); + blockingCallSpeak("le fou barre", delegate); + ArgumentCaptor<SynthesisRequest> req2 = LittleMock.createCaptor(); + LittleMock.verify(delegate, LittleMock.times(1)).onSynthesizeText(req2.capture(), + LittleMock.<SynthesisCallback>anyObject()); + + // The params are basically unchanged. + assertEquals("eng", req2.getValue().getLanguage()); + assertEquals("USA", req2.getValue().getCountry()); + assertEquals("", req2.getValue().getVariant()); + } + + + public void testGetLanguage_invalidReturnValues() { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // Test1: Simple end to end test. Ensure that bad return values + // are dealt with appropriately. + LittleMock.doReturn(null).when(delegate).onGetLanguage(); + Locale returnVal = mTts.getLanguage(); + assertNull(returnVal); + + + // Bad value 2. An array of length < 3. + LittleMock.doReturn(new String[] {"eng", "usa"}).when(delegate).onGetLanguage(); + returnVal = mTts.getLanguage(); + assertNull(returnVal); + } + + public void testGetLanguage_validReturnValues() { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // A correct value. + LittleMock.doReturn(new String[] {"eng", "usa", ""}).when(delegate).onGetLanguage(); + Locale returnVal = mTts.getLanguage(); + + // Note: This is not the same as Locale.US . Well tough luck for + // being the only component of the entire framework that standardized + // three letter country and language codes. + assertEquals(new Locale("eng", "USA", ""), returnVal); + } + + public void testIsLanguageAvailable() { + IDelegate delegate = LittleMock.mock(IDelegate.class); + MockableTextToSpeechService.setMocker(delegate); + + // Test1: Simple end to end test. + LittleMock.doReturn(TextToSpeech.LANG_COUNTRY_AVAILABLE).when( + delegate).onIsLanguageAvailable("eng", "USA", ""); + + assertEquals(TextToSpeech.LANG_COUNTRY_AVAILABLE, mTts.isLanguageAvailable(Locale.US)); + LittleMock.verify(delegate, LittleMock.times(1)).onIsLanguageAvailable( + "eng", "USA", ""); + } + + + private void blockingCallSpeak(String speech, IDelegate mock) throws + InterruptedException { + final CountDownLatch latch = new CountDownLatch(1); + doCountDown(latch).when(mock).onSynthesizeText(LittleMock.<SynthesisRequest>anyObject(), + LittleMock.<SynthesisCallback>anyObject()); + mTts.speak(speech, TextToSpeech.QUEUE_ADD, null); + + awaitCountDown(latch, 5, TimeUnit.SECONDS); + } + + private void blockingInitAndVerify(final String engine, int errorCode) throws + InterruptedException { + TextToSpeech.OnInitListener listener = LittleMock.mock( + TextToSpeech.OnInitListener.class); + + final CountDownLatch latch = new CountDownLatch(1); + doCountDown(latch).when(listener).onInit(errorCode); + + mTts = new TextToSpeech(getInstrumentation().getTargetContext(), + listener, engine, MOCK_PACKAGE, false /* use fallback package */); + + awaitCountDown(latch, 5, TimeUnit.SECONDS); + } + + public interface CountDownBehaviour extends Behaviour { + /** Used to mock methods that return a result. */ + Behaviour andReturn(Object result); + } + + public static CountDownBehaviour doCountDown(final CountDownLatch latch) { + return new CountDownBehaviour() { + @Override + public <T> T when(T mock) { + return LittleMock.doAnswer(new Callable<Void>() { + @Override + public Void call() throws Exception { + latch.countDown(); + return null; + } + }).when(mock); + } + + @Override + public Behaviour andReturn(final Object result) { + return new Behaviour() { + @Override + public <T> T when(T mock) { + return LittleMock.doAnswer(new Callable<Object>() { + @Override + public Object call() throws Exception { + latch.countDown(); + return result; + } + }).when(mock); + } + }; + } + }; + } + + public static void awaitCountDown(CountDownLatch latch, long timeout, TimeUnit unit) + throws InterruptedException { + Assert.assertTrue("Waited too long for method call", latch.await(timeout, unit)); + } +} |