diff --git a/build.gradle b/build.gradle index 576611ea..28ebe199 100755 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = "1.2.51" + ext.kotlin_version = "1.3.10" repositories { google() jcenter() @@ -11,7 +11,7 @@ buildscript { classpath 'com.android.tools.build:gradle:3.2.1' classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlin_version" - classpath 'io.fabric.tools:gradle:1.+' + classpath 'io.fabric.tools:gradle:1.26.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -62,9 +62,7 @@ subprojects { ext { minSdkVersion = 19 targetSdkVersion = 27 - compileSdkVersion = 27 - buildToolsVersion = "27.0.3" - kotlinVersion = "1.2.51" - supportVersion = "27.0.1" - + compileSdkVersion = 28 + buildToolsVersion = "28.0.3" + supportVersion = "28.0.0" } \ No newline at end of file diff --git a/mobile/build.gradle b/mobile/build.gradle index 01f850bd..4f9102f1 100755 --- a/mobile/build.gradle +++ b/mobile/build.gradle @@ -44,6 +44,10 @@ android { dataBinding { enabled=true } + + testOptions { + unitTests.returnDefaultValues = true + } } repositories { @@ -54,41 +58,36 @@ repositories { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation "com.android.support:appcompat-v7:$rootProject.supportVersion" - implementation "com.android.support:design:$rootProject.supportVersion" - implementation "com.android.support:support-v4:$rootProject.supportVersion" + implementation "org.jetbrains.kotlin:kotlin-stdlib:$rootProject.kotlin_version" - // layout deps + // Support Libraries and Google Play Services + implementation "com.android.support:appcompat-v7:$rootProject.supportVersion" implementation "com.android.support:cardview-v7:$rootProject.supportVersion" + implementation "com.android.support:design:$rootProject.supportVersion" implementation "com.android.support:recyclerview-v7:$rootProject.supportVersion" + implementation "com.android.support:support-core-utils:$rootProject.supportVersion" + implementation 'com.google.android.gms:play-services-wearable:16.0.1' - implementation "com.android.support:palette-v7:$rootProject.supportVersion" + implementation 'org.java-websocket:Java-WebSocket:1.3.0' - // Unit test dependencies - testImplementation 'org.mockito:mockito-core:1.10.19' - testImplementation 'org.powermock:powermock-api-mockito:1.6.4' - testImplementation 'org.powermock:powermock-module-junit4-rule-agent:1.6.4' - testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.4' - testImplementation 'org.powermock:powermock-module-junit4:1.6.4' - testImplementation 'junit:junit:4.12' - // Instrumentation dependencies - androidTestImplementation 'com.android.support.test.espresso:espresso-core:2.2.2' - androidTestImplementation 'com.android.support.test:runner:0.5' - androidTestImplementation "com.android.support:support-annotations:$rootProject.supportVersion" - implementation('com.crashlytics.sdk.android:crashlytics:2.5.7@aar') { + implementation 'io.reactivex.rxjava2:rxjava:2.2.3' + implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' + + implementation('com.crashlytics.sdk.android:crashlytics:2.9.6@aar') { transitive = true } - implementation 'com.google.android.gms:play-services-wearable:9.4.0' - wearApp project(':wear') + implementation project(':shared') - //kotlin - implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - //rxjava,rxandroid - implementation 'io.reactivex.rxjava2:rxjava:2.2.3' - implementation 'io.reactivex.rxjava2:rxandroid:2.1.0' + wearApp project(':wear') - implementation 'org.java-websocket:Java-WebSocket:1.3.0' + // Unit test dependencies + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.3.1' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.3.1' + testImplementation 'io.mockk:mockk:1.8.13.kotlin13' - implementation "com.android.support:support-core-utils:$rootProject.supportVersion" + // Instrumentation dependencies + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' + androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation "com.android.support:support-annotations:$rootProject.supportVersion" } diff --git a/mobile/src/main/AndroidManifest.xml b/mobile/src/main/AndroidManifest.xml index 8f7c9ceb..bf431d2b 100755 --- a/mobile/src/main/AndroidManifest.xml +++ b/mobile/src/main/AndroidManifest.xml @@ -27,7 +27,6 @@ - - . - * - */ - -package mycroft.ai - -import android.content.Context -import android.os.Bundle -import android.util.Log - -import java.net.ServerSocket - - -import android.net.nsd.NsdManager -import android.net.nsd.NsdManager.DiscoveryListener -import android.net.nsd.NsdManager.ResolveListener -import android.net.nsd.NsdServiceInfo -import android.annotation.SuppressLint -import android.app.Activity - -@SuppressLint("NewApi") -class DiscoveryActivity : Activity() { - - internal lateinit var mDiscoveryListener: DiscoveryListener - - internal var mServiceName: String? = null - internal var mServiceInfo: NsdServiceInfo? = null - internal var mServerSocket: ServerSocket? = null - internal var mLocalPort: Int = 0 - - internal lateinit var mNsdManager: NsdManager - - internal val TAG = "ServiceDiscovery" - internal val SERVICE_TYPE = "_mycroft._tcp" - internal val SERVICE_NAME = "MycroftAI Websocket" - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - setContentView(R.layout.activity_main) - - mNsdManager = applicationContext.getSystemService(Context.NSD_SERVICE) as NsdManager - - initializeDiscoveryListener() - - mNsdManager.discoverServices( - SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener) - - } - - fun initializeDiscoveryListener() { - - // Instantiate a new DiscoveryListener - mDiscoveryListener = object : NsdManager.DiscoveryListener { - - // Called as soon as service discovery begins. - override fun onDiscoveryStarted(regType: String) { - Log.d(TAG, "Service discovery started") - } - - override fun onServiceFound(service: NsdServiceInfo) { - // A service was found! Do something with it. - Log.d(TAG, "Service discovery success: $service") - if (service.serviceType != SERVICE_TYPE) { - // Service type is the string containing the protocol and - // transport layer for this service. - Log.d(TAG, "Mycroft found!: " + service.serviceType + " " + service.host + " " + service.port) - resolveService(service) - } - } - - override fun onServiceLost(service: NsdServiceInfo) { - // When the network service is no longer available. - // Internal bookkeeping code goes here. - Log.e(TAG, "service lost: $service") - } - - override fun onDiscoveryStopped(serviceType: String) { - Log.i(TAG, "Discovery stopped: $serviceType") - } - - override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) { - Log.e(TAG, "Discovery failed: Error code: $errorCode") - mNsdManager.stopServiceDiscovery(this) - } - - override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) { - Log.e(TAG, "Discovery failed: Error code: $errorCode") - mNsdManager.stopServiceDiscovery(this) - } - } - } - - private fun resolveService(service: NsdServiceInfo) { - mNsdManager.resolveService(service, object : ResolveListener { - - override fun onServiceResolved(serviceInfo: NsdServiceInfo) { - Log.d(TAG, "Resolving service...") - Log.i(TAG, serviceInfo.host.toString()) - Log.i(TAG, "Port: " + serviceInfo.port) - } - - override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { - // TODO Auto-generated method stub - Log.d(TAG, "Service resolve failed!") - } - }) - } -} \ No newline at end of file diff --git a/mobile/src/main/java/mycroft/ai/MainActivity.kt b/mobile/src/main/java/mycroft/ai/MainActivity.kt index d3264582..eb5a9029 100644 --- a/mobile/src/main/java/mycroft/ai/MainActivity.kt +++ b/mobile/src/main/java/mycroft/ai/MainActivity.kt @@ -118,9 +118,6 @@ class MainActivity : AppCompatActivity() { } registerReceivers() - - // start the discovery activity (testing only) - // startActivity(new Intent(this, DiscoveryActivity.class)); } override fun onCreateOptionsMenu(menu: Menu): Boolean { diff --git a/mobile/src/main/java/mycroft/ai/TTSManager.kt b/mobile/src/main/java/mycroft/ai/TTSManager.kt index a183064c..65509d51 100755 --- a/mobile/src/main/java/mycroft/ai/TTSManager.kt +++ b/mobile/src/main/java/mycroft/ai/TTSManager.kt @@ -46,11 +46,14 @@ import java.util.Locale */ class TTSManager { + val notInitializedErrorMessage = "TTS Not Initialized" + val initializationFailedErrorMessage = "Initialization Failed!" /** * Backing TTS for this instance. Should not (ever) be null. */ private lateinit var mTts: TextToSpeech + /** * Whether the TTS is available for use (i.e. loaded into memory) */ @@ -71,7 +74,7 @@ class TTSManager { logError("This Language is not supported") } } else { - logError("Initialization Failed!") + logError(initializationFailedErrorMessage) } } @@ -108,7 +111,7 @@ class TTSManager { if (isLoaded) mTts.speak(text, TextToSpeech.QUEUE_ADD, null) else { - logError("TTS Not Initialized") + logError(notInitializedErrorMessage) } } @@ -117,7 +120,7 @@ class TTSManager { if (isLoaded) mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null) else - logError("TTS Not Initialized") + logError(notInitializedErrorMessage) } /** diff --git a/mobile/src/main/java/mycroft/ai/utils/NetworkAutoDiscoveryUtil.kt b/mobile/src/main/java/mycroft/ai/utils/NetworkAutoDiscoveryUtil.kt deleted file mode 100755 index 19cc2108..00000000 --- a/mobile/src/main/java/mycroft/ai/utils/NetworkAutoDiscoveryUtil.kt +++ /dev/null @@ -1,167 +0,0 @@ -/* - * Copyright (c) 2017. Mycroft AI, Inc. - * - * This file is part of Mycroft-Android a client for Mycroft Core. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package mycroft.ai.utils - -import android.content.Context -import android.net.nsd.NsdServiceInfo -import android.net.nsd.NsdManager -import android.util.Log - -/** - * Created by paul on 2016/06/28. - */ -class NetworkAutoDiscoveryUtil(internal var mContext: Context) { - private var mServiceName = "MycroftAI Websocket" - private var chosenServiceInfo: NsdServiceInfo? = null - private var mNsdManager: NsdManager = mContext.getSystemService(Context.NSD_SERVICE) as NsdManager - - //declare late init as initialisation is after the fact. - internal lateinit var mResolveListener: NsdManager.ResolveListener - - private var mDiscoveryListener: NsdManager.DiscoveryListener? = null - private var mRegistrationListener: NsdManager.RegistrationListener? = null - - - fun initializeNsd() { - initializeResolveListener() - //mNsdManager.init(mContext.getMainLooper(), this); - } - - fun initializeDiscoveryListener() { - mDiscoveryListener = object : NsdManager.DiscoveryListener { - override fun onDiscoveryStarted(regType: String) { - Log.d(TAG, "Service discovery started") - } - - override fun onServiceFound(service: NsdServiceInfo) { - Log.d(TAG, "Service discovery success$service") - if (service.serviceType != SERVICE_TYPE) { - Log.d(TAG, "Unknown Service Type: " + service.serviceType) - } else if (service.serviceName == mServiceName) { - Log.d(TAG, "Same machine: $mServiceName") - } else if (service.serviceName.contains(mServiceName)) { - mNsdManager.resolveService(service, mResolveListener) - } - } - - override fun onServiceLost(service: NsdServiceInfo) { - Log.e(TAG, "service lost$service") - if (chosenServiceInfo == service) { - chosenServiceInfo = null - } - } - - override fun onDiscoveryStopped(serviceType: String) { - Log.i(TAG, "Discovery stopped: $serviceType") - } - - override fun onStartDiscoveryFailed(serviceType: String, errorCode: Int) { - Log.e(TAG, "Discovery failed: Error code:$errorCode") - } - - override fun onStopDiscoveryFailed(serviceType: String, errorCode: Int) { - Log.e(TAG, "Discovery failed: Error code:$errorCode") - } - } - } - - fun initializeResolveListener() { - mResolveListener = object : NsdManager.ResolveListener { - override fun onResolveFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { - Log.e(TAG, "Resolve failed$errorCode") - } - - override fun onServiceResolved(serviceInfo: NsdServiceInfo) { - Log.e(TAG, "Resolve Succeeded. $serviceInfo") - if (serviceInfo.serviceName == mServiceName) { - Log.d(TAG, "Same IP.") - return - } - chosenServiceInfo = serviceInfo - } - } - } - - fun initializeRegistrationListener() { - mRegistrationListener = object : NsdManager.RegistrationListener { - override fun onServiceRegistered(NsdServiceInfo: NsdServiceInfo) { - mServiceName = NsdServiceInfo.serviceName - Log.d(TAG, "Service registered: $mServiceName") - } - - override fun onRegistrationFailed(arg0: NsdServiceInfo, arg1: Int) { - Log.d(TAG, "Service registration failed: $arg1") - } - - override fun onServiceUnregistered(arg0: NsdServiceInfo) { - Log.d(TAG, "Service unregistered: " + arg0.serviceName) - } - - override fun onUnregistrationFailed(serviceInfo: NsdServiceInfo, errorCode: Int) { - Log.d(TAG, "Service unregistration failed: $errorCode") - } - } - } - - fun registerService(port: Int) { - tearDown() // Cancel any previous registration request - initializeRegistrationListener() - val serviceInfo = NsdServiceInfo() - serviceInfo.port = port - serviceInfo.serviceName = mServiceName - serviceInfo.serviceType = SERVICE_TYPE - mNsdManager.registerService( - serviceInfo, NsdManager.PROTOCOL_DNS_SD, mRegistrationListener) - } - - fun discoverServices() { - stopDiscovery() // Cancel any existing discovery request - initializeDiscoveryListener() - mNsdManager.discoverServices( - SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener) - } - - fun stopDiscovery() { - if (mDiscoveryListener != null) { - try { - mNsdManager.stopServiceDiscovery(mDiscoveryListener) - } finally { - } - mDiscoveryListener = null - } - } - - fun tearDown() { - if (mRegistrationListener != null) { - try { - mNsdManager.unregisterService(mRegistrationListener) - } finally { - } - mRegistrationListener = null - } - } - - companion object { - - private val TAG = "NetworkDiscovery" - private val SERVICE_TYPE = " _mycroft._tcp" - } -} diff --git a/mobile/src/test/java/mycroft/ai/ExampleUnitTest.java b/mobile/src/test/java/mycroft/ai/ExampleUnitTest.java deleted file mode 100755 index 5de091b1..00000000 --- a/mobile/src/test/java/mycroft/ai/ExampleUnitTest.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2017. Mycroft AI, Inc. - * - * This file is part of Mycroft-Android a client for Mycroft Core. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package mycroft.ai; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * Example local unit test, which will execute on the development machine (host). - * - * @see Testing documentation - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() throws Exception { - assertEquals(4, 2 + 2); - } -} \ No newline at end of file diff --git a/mobile/src/test/java/mycroft/ai/LogAnswer.java b/mobile/src/test/java/mycroft/ai/LogAnswer.java deleted file mode 100755 index 96396391..00000000 --- a/mobile/src/test/java/mycroft/ai/LogAnswer.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2017. Mycroft AI, Inc. - * - * This file is part of Mycroft-Android a client for Mycroft Core. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package mycroft.ai; - -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import java.io.PrintStream; -import java.nio.charset.Charset; -import java.util.Locale; - -/** - * Useful for mocking {@link android.util.Log} static methods. - *

- * Use it like so: - * {@code - * Mockito.when(Log.v(anyString(), anyString())).then(new LogAnswer(System.out)); - * } - *

- * - * @author Philip Cohn-Cort - */ -public class LogAnswer implements Answer { - - protected final PrintStream stream; - - public LogAnswer(PrintStream stream) { - this.stream = stream; - } - - @Override - public Integer answer(InvocationOnMock invocation) throws Throwable { - String tag = invocation.getArgumentAt(0, String.class); - String msg = invocation.getArgumentAt(1, String.class); - - String name = invocation.getMethod().getName(); - - String format = String.format(Locale.US, "[Log.%s] %s: %s", name, tag, msg); - stream.println(format); - - return format.getBytes(Charset.forName("UTF8")).length; - } -} \ No newline at end of file diff --git a/mobile/src/test/java/mycroft/ai/TTSManagerTest.java b/mobile/src/test/java/mycroft/ai/TTSManagerTest.java deleted file mode 100755 index 15127220..00000000 --- a/mobile/src/test/java/mycroft/ai/TTSManagerTest.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2017. Mycroft AI, Inc. - * - * This file is part of Mycroft-Android a client for Mycroft Core. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - */ - -package mycroft.ai; - -import android.os.Bundle; -import android.speech.tts.TextToSpeech; -import android.util.Log; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; - -import java.util.HashMap; -import java.util.Locale; - -import static org.junit.Assert.*; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.atLeast; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.mockStatic; -import static org.powermock.api.mockito.PowerMockito.when; - -/** - * @author Philip Cohn-Cort - */ -@RunWith(PowerMockRunner.class) -@PrepareForTest({Log.class}) -public class TTSManagerTest { - - @Before - public void setUp() throws Exception { - mockStatic(Log.class); - - LogAnswer stdOut = new LogAnswer(System.out); - when(Log.v(anyString(), anyString())).then(stdOut); - when(Log.d(anyString(), anyString())).then(stdOut); - when(Log.i(anyString(), anyString())).then(stdOut); - - LogAnswer stdErr = new LogAnswer(System.err); - when(Log.w(anyString(), anyString())).then(stdErr); - when(Log.e(anyString(), anyString())).then(stdErr); - when(Log.wtf(anyString(), anyString())).then(stdErr); - } - - @Test - public void testAddingToQueueBeforeIsLoaded() throws Exception { - TextToSpeech mock = mock(TextToSpeech.class); - TTSManager ttsManager = new TTSManager(mock); - - TTSManager.TTSListener mockListener = mock(TTSManager.TTSListener.class); - ttsManager.setTTSListener(mockListener); - - ttsManager.addQueue("text a"); - - verify(mockListener).onError("TTS Not Initialized"); - } - - @Test - public void testAddingToQueueAfterIsLoaded() throws Exception { - TextToSpeech tts = mock(TextToSpeech.class); - when(tts.setLanguage(any(Locale.class))).thenReturn(TextToSpeech.LANG_AVAILABLE); - - TTSManager ttsManager = new TTSManager(tts); - - TTSManager.TTSListener mockListener = mock(TTSManager.TTSListener.class); - ttsManager.setTTSListener(mockListener); - - ttsManager.getOnInitListener().onInit(TextToSpeech.SUCCESS); - - verify(mockListener, never()).onError(anyString()); - - ttsManager.addQueue("text a"); - - verify(mockListener, never()).onError(anyString()); - } - - @Test - public void testAddingToQueueTriggersSpeak() throws Exception { - TextToSpeech tts = mock(TextToSpeech.class); - when(tts.setLanguage(any(Locale.class))).thenReturn(TextToSpeech.LANG_AVAILABLE); - - TTSManager ttsManager = new TTSManager(tts); - - TTSManager.TTSListener mockListener = mock(TTSManager.TTSListener.class); - ttsManager.setTTSListener(mockListener); - - ttsManager.getOnInitListener().onInit(TextToSpeech.SUCCESS); - - ttsManager.addQueue("text a"); - - // Make sure that one of the speak methods was called, but we don't care which - - ArgumentCaptor paramCaptor1 = ArgumentCaptor.forClass(Integer.class); - ArgumentCaptor paramCaptor2 = ArgumentCaptor.forClass(Integer.class); - - //noinspection unchecked - verify(tts, atLeast(0)).speak(anyString(), paramCaptor1.capture(), any(HashMap.class)); - verify(tts, atLeast(0)).speak(any(CharSequence.class), paramCaptor2.capture(), any(Bundle.class), anyString()); - - assertTrue("One of the speak methods should have been called.", - !paramCaptor1.getAllValues().isEmpty() - || - !paramCaptor2.getAllValues().isEmpty() - ); - } - - @Test - public void testFailureDoesNotSetIsLoaded() throws Exception { - TextToSpeech tts = mock(TextToSpeech.class); - when(tts.setLanguage(any(Locale.class))).thenReturn(TextToSpeech.LANG_AVAILABLE); - - TTSManager ttsManager = new TTSManager(tts); - - TTSManager.TTSListener mockListener = mock(TTSManager.TTSListener.class); - ttsManager.setTTSListener(mockListener); - - ttsManager.getOnInitListener().onInit(TextToSpeech.ERROR); - - ttsManager.addQueue("text a"); - - verify(mockListener, times(2)).onError(anyString()); - } -} \ No newline at end of file diff --git a/mobile/src/test/java/mycroft/ai/TTSManagerTest.kt b/mobile/src/test/java/mycroft/ai/TTSManagerTest.kt new file mode 100644 index 00000000..7ec6e8bd --- /dev/null +++ b/mobile/src/test/java/mycroft/ai/TTSManagerTest.kt @@ -0,0 +1,61 @@ +package mycroft.ai + +import android.speech.tts.TextToSpeech +import io.mockk.impl.annotations.RelaxedMockK +import io.mockk.junit5.MockKExtension +import io.mockk.verify +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(MockKExtension::class) +class TTSManagerTest { + private val someSpeech = "some speech" + + private lateinit var subject: TTSManager + + @RelaxedMockK + private lateinit var textToSpeech: TextToSpeech + + @RelaxedMockK + private lateinit var ttsListener: TTSManager.TTSListener + + @BeforeEach + fun setUp() { + subject = TTSManager(textToSpeech) + } + + @Test + fun testAddQueue_BeforeIsLoaded_CallsOnError() { + subject.setTTSListener(ttsListener) + subject.addQueue(someSpeech) + + verify(exactly = 1) { ttsListener.onError(eq(subject.notInitializedErrorMessage)) } + } + + @Test + fun testAddQueue_WhenLoaded_DoesNotCallOnError() { + subject.onInitListener.onInit(TextToSpeech.SUCCESS) + verify(exactly = 0) { ttsListener.onError(any()) } + subject.addQueue(someSpeech) + verify(exactly = 0) { ttsListener.onError(any()) } + } + + @Test + fun testAddQueue_WhenLoaded_TriggersSpeak() { + subject.onInitListener.onInit(TextToSpeech.SUCCESS) + subject.addQueue(someSpeech) + verify(exactly = 1) { textToSpeech.speak(any(), any(), any()) } + } + + @Test + fun testInitFailure_DoesNotSetLoadedTrue() { + subject.setTTSListener(ttsListener) + subject.onInitListener.onInit(TextToSpeech.ERROR) + subject.addQueue(someSpeech) + verify(exactly = 1) { ttsListener.onError(eq(subject.initializationFailedErrorMessage)) } + verify(exactly = 1) { ttsListener.onError(eq(subject.notInitializedErrorMessage)) } + + } +} \ No newline at end of file