diff --git a/binding/android/PorcupineTestApp/porcupine-test-app/build.gradle b/binding/android/PorcupineTestApp/porcupine-test-app/build.gradle index e7bde2ccc..a45d2845d 100644 --- a/binding/android/PorcupineTestApp/porcupine-test-app/build.gradle +++ b/binding/android/PorcupineTestApp/porcupine-test-app/build.gradle @@ -114,10 +114,12 @@ android { androidTest { java { if (System.getProperty("testBuildType", "debug") == "perf") { - exclude "**/PorcupineTest.java" + exclude "**/StandardTests.java" + exclude "**/LanguageTests.java" exclude "**/IntegrationTest.java" } else if (System.getProperty("testBuildType", "debug") == "integ") { - exclude "**/PorcupineTest.java" + exclude "**/StandardTests.java" + exclude "**/LanguageTests.java" exclude "**/PerformanceTest.java" } else { exclude "**/IntegrationTest.java" diff --git a/binding/android/PorcupineTestApp/porcupine-test-app/src/androidTest/java/ai/picovoice/porcupine/testapp/LanguageTests.java b/binding/android/PorcupineTestApp/porcupine-test-app/src/androidTest/java/ai/picovoice/porcupine/testapp/LanguageTests.java new file mode 100644 index 000000000..61eb77187 --- /dev/null +++ b/binding/android/PorcupineTestApp/porcupine-test-app/src/androidTest/java/ai/picovoice/porcupine/testapp/LanguageTests.java @@ -0,0 +1,123 @@ +/* + Copyright 2025 Picovoice Inc. + + You may not use this file except in compliance with the license. A copy of the license is + located in the "LICENSE" file accompanying this source. + + 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 ai.picovoice.porcupine.testapp; + +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Objects; + +import ai.picovoice.porcupine.Porcupine; + + +@RunWith(Parameterized.class) +public class LanguageTests extends BaseTest { + + @Parameterized.Parameter(value = 0) + public String modelFile; + + @Parameterized.Parameter(value = 1) + public String[] keywordFiles; + + @Parameterized.Parameter(value = 2) + public String testAudioFile; + + @Parameterized.Parameter(value = 3) + public int[] expectedResults; + + @Parameterized.Parameters(name = "{0}") + public static Collection initParameters() throws IOException { + String testDataJsonString = getTestDataString(); + + JsonObject testDataJson = JsonParser.parseString(testDataJsonString).getAsJsonObject(); + JsonArray multipleKeywordDataJson = testDataJson.getAsJsonObject("tests").getAsJsonArray("multipleKeyword"); + + List parameters = new ArrayList<>(); + for (int i = 0; i < multipleKeywordDataJson.size(); i++) { + JsonObject testData = multipleKeywordDataJson.get(i).getAsJsonObject(); + String language = testData.get("language").getAsString(); + JsonArray keywords = testData.getAsJsonArray("wakewords"); + JsonArray groundTruthJson = testData.getAsJsonArray("groundTruth"); + + String modelFile = String.format("model_files/porcupine_params_%s.pv", language); + String[] keywordFiles = new String[keywords.size()]; + for (int j = 0; j < keywords.size(); j++) { + String keyword = keywords.get(j).getAsString(); + keywordFiles[j] = String.format("keyword_files/%s/%s_android.ppn", language, keyword); + } + String audioFile = String.format("audio_samples/multiple_keywords_%s.wav", language); + int[] groundTruth = new int[groundTruthJson.size()]; + for (int j = 0; j < groundTruthJson.size(); j++) { + groundTruth[j] = groundTruthJson.get(j).getAsInt(); + } + + if (Objects.equals(language, "en")) { + modelFile = "model_files/porcupine_params.pv"; + audioFile = "audio_samples/multiple_keywords.wav"; + } + + parameters.add(new Object[] { + modelFile, + keywordFiles, + audioFile, + groundTruth + }); + } + + return parameters; + } + + + @Test + public void testProcess() throws Exception { + String modelPath = new File(testResourcesPath, modelFile).getAbsolutePath(); + String[] keywordPaths = new String[keywordFiles.length]; + for (int i = 0; i < keywordFiles.length; i++) { + keywordPaths[i] = new File(testResourcesPath, keywordFiles[i]).getAbsolutePath(); + + } + Porcupine p = new Porcupine.Builder() + .setAccessKey(accessKey) + .setModelPath(modelPath) + .setKeywordPaths(keywordPaths) + .build(appContext); + + assertTrue(p.getVersion() != null && !p.getVersion().isEmpty()); + assertTrue(p.getFrameLength() > 0); + assertTrue(p.getSampleRate() > 0); + + File testAudio = new File(testResourcesPath, testAudioFile); + ArrayList detectionResults = processTestAudio(p, testAudio); + p.delete(); + + assertSame(expectedResults.length, detectionResults.size()); + for (int i = 0; i < expectedResults.length; i++) { + assertSame(detectionResults.get(i), expectedResults[i]); + } + + p.delete(); + } +} diff --git a/binding/android/PorcupineTestApp/porcupine-test-app/src/androidTest/java/ai/picovoice/porcupine/testapp/PorcupineTest.java b/binding/android/PorcupineTestApp/porcupine-test-app/src/androidTest/java/ai/picovoice/porcupine/testapp/PorcupineTest.java deleted file mode 100644 index 05bde7462..000000000 --- a/binding/android/PorcupineTestApp/porcupine-test-app/src/androidTest/java/ai/picovoice/porcupine/testapp/PorcupineTest.java +++ /dev/null @@ -1,438 +0,0 @@ -/* - Copyright 2022 Picovoice Inc. - - You may not use this file except in compliance with the license. A copy of the license is - located in the "LICENSE" file accompanying this source. - - 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 ai.picovoice.porcupine.testapp; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; - -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; - -import org.junit.Test; -import org.junit.experimental.runners.Enclosed; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Objects; - -import ai.picovoice.porcupine.Porcupine; -import ai.picovoice.porcupine.PorcupineException; - - -@RunWith(Enclosed.class) -public class PorcupineTest { - - public static class StandardTests extends BaseTest { - - @Test - public void testInitSuccessWithSingleBuiltIn() throws PorcupineException { - Porcupine p = new Porcupine.Builder() - .setAccessKey(accessKey) - .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) - .build(appContext); - - assertTrue(p.getVersion() != null && !p.getVersion().equals("")); - assertTrue(p.getFrameLength() > 0); - assertTrue(p.getSampleRate() > 0); - - p.delete(); - } - - @Test - public void testInitSuccessWithMultipleBuiltIns() throws PorcupineException { - Porcupine.BuiltInKeyword[] inputBuiltInKeywords = new Porcupine.BuiltInKeyword[]{ - Porcupine.BuiltInKeyword.ALEXA, - Porcupine.BuiltInKeyword.GRASSHOPPER, - Porcupine.BuiltInKeyword.PICOVOICE, - Porcupine.BuiltInKeyword.TERMINATOR - }; - - Porcupine p = new Porcupine.Builder() - .setAccessKey(accessKey) - .setKeywords(inputBuiltInKeywords) - .build(appContext); - - assertTrue(p.getVersion() != null && !p.getVersion().equals("")); - assertTrue(p.getFrameLength() > 0); - assertTrue(p.getSampleRate() > 0); - - p.delete(); - } - - @Test - public void testInitSuccessWithCustomArguments() throws PorcupineException { - File keywordPath = new File(testResourcesPath, "keyword_files/en/hey_barista_android.ppn"); - File modelPath = new File(testResourcesPath, "model_files/porcupine_params.pv"); - Porcupine p = new Porcupine.Builder() - .setAccessKey(accessKey) - .setModelPath(modelPath.getAbsolutePath()) - .setKeywordPath(keywordPath.getAbsolutePath()) - .setSensitivity(0.25f) - .build(appContext); - - assertTrue(p.getVersion() != null && !p.getVersion().equals("")); - assertTrue(p.getFrameLength() > 0); - assertTrue(p.getSampleRate() > 0); - - p.delete(); - } - - @Test - public void testInitSuccessWithMultipleCustomKeywordsAndSensitivities() throws PorcupineException { - File keywordPath = new File(testResourcesPath, "keyword_files/en/hey_barista_android.ppn"); - File keywordPath2 = new File(testResourcesPath, "keyword_files/en/pico_clock_android.ppn"); - String[] keywordPaths = new String[]{keywordPath.getAbsolutePath(), keywordPath2.getAbsolutePath()}; - Porcupine p = new Porcupine.Builder() - .setAccessKey(accessKey) - .setKeywordPaths(keywordPaths) - .setSensitivities(new float[]{0.35f, 0.6f}) - .build(appContext); - - assertTrue(p.getVersion() != null && !p.getVersion().equals("")); - assertTrue(p.getFrameLength() > 0); - assertTrue(p.getSampleRate() > 0); - - p.delete(); - } - - @Test - public void testInitFailWithMismatchedLanguage() { - boolean didFail = false; - File keywordPath = new File(testResourcesPath, "keyword_files/de/ananas_android.ppn"); - File modelPath = new File(testResourcesPath, "model_files/porcupine_params.pv"); - try { - new Porcupine.Builder() - .setAccessKey(accessKey) - .setModelPath(modelPath.getAbsolutePath()) - .setKeywordPath(keywordPath.getAbsolutePath()) - .build(appContext); - } catch (PorcupineException e) { - didFail = true; - } - - assertTrue(didFail); - } - - @Test - public void testInitFailWithInvalidModelPath() { - boolean didFail = false; - File modelPath = new File(testResourcesPath, "bad_path/bad_path.pv"); - try { - new Porcupine.Builder() - .setAccessKey(accessKey) - .setModelPath(modelPath.getAbsolutePath()) - .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) - .build(appContext); - } catch (PorcupineException e) { - didFail = true; - } - - assertTrue(didFail); - } - - @Test - public void testInitFailWithInvalidSensitivity() { - boolean didFail = false; - try { - new Porcupine.Builder() - .setAccessKey(accessKey) - .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) - .setSensitivity(10) - .build(appContext); - } catch (PorcupineException e) { - didFail = true; - } - - assertTrue(didFail); - } - - @Test - public void testInitFailWithMismatchedSensitivityCount() { - boolean didFail = false; - try { - new Porcupine.Builder() - .setAccessKey(accessKey) - .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) - .setSensitivities(new float[]{0.4f, 0.8f}) - .build(appContext); - } catch (PorcupineException e) { - didFail = true; - } - - assertTrue(didFail); - } - - @Test - public void testInitFailWithNoKeywords() { - boolean didFail = false; - try { - new Porcupine.Builder() - .setAccessKey(accessKey) - .build(appContext); - } catch (PorcupineException e) { - didFail = true; - } - - assertTrue(didFail); - } - - @Test - public void testInitFailWithInvalidKeywordPath() { - boolean didFail = false; - File keywordPath = new File(testResourcesPath, "bad_path/bad_path.ppn"); - try { - new Porcupine.Builder() - .setAccessKey(accessKey) - .setKeywordPath(keywordPath.getAbsolutePath()) - .build(appContext); - } catch (PorcupineException e) { - didFail = true; - } - - assertTrue(didFail); - } - - @Test - public void testInitFailWithBuiltInAndCustom() { - File keywordPath = new File(testResourcesPath, "keyword_files/en/hey_barista_android.ppn"); - boolean didFail = false; - try { - new Porcupine.Builder() - .setAccessKey(accessKey) - .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) - .setKeywordPath(keywordPath.getAbsolutePath()) - .build(appContext); - } catch (PorcupineException e) { - didFail = true; - } - - assertTrue(didFail); - } - - @Test - public void testInitFailWithWrongKeywordPlatform() { - boolean didFail = false; - File keywordPath = new File(testResourcesPath, "keyword_files/en/alexa_linux.ppn"); - try { - new Porcupine.Builder() - .setAccessKey(accessKey) - .setKeywordPath(keywordPath.getAbsolutePath()) - .build(appContext); - } catch (PorcupineException e) { - didFail = true; - } - - assertTrue(didFail); - } - - @Test - public void testProcSuccessSingleBuiltIn() throws Exception { - Porcupine p = new Porcupine.Builder() - .setAccessKey(accessKey) - .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) - .build(appContext); - - File testAudio = new File(testResourcesPath, "audio_samples/porcupine.wav"); - ArrayList detectionResults = processTestAudio(p, testAudio); - p.delete(); - - assertEquals(1, detectionResults.size()); - assertEquals(0, (int) detectionResults.get(0)); - } - - @Test - public void testProcSuccessMultipleBuiltIn() throws Exception { - Porcupine.BuiltInKeyword[] inputBuiltInKeywords = new Porcupine.BuiltInKeyword[]{ - Porcupine.BuiltInKeyword.ALEXA, - Porcupine.BuiltInKeyword.AMERICANO, - Porcupine.BuiltInKeyword.BLUEBERRY, - Porcupine.BuiltInKeyword.BUMBLEBEE, - Porcupine.BuiltInKeyword.GRAPEFRUIT, - Porcupine.BuiltInKeyword.GRASSHOPPER, - Porcupine.BuiltInKeyword.PICOVOICE, - Porcupine.BuiltInKeyword.PORCUPINE, - Porcupine.BuiltInKeyword.TERMINATOR - }; - - Porcupine.BuiltInKeyword[] expectedResults = new Porcupine.BuiltInKeyword[]{ - Porcupine.BuiltInKeyword.PORCUPINE, - Porcupine.BuiltInKeyword.ALEXA, - Porcupine.BuiltInKeyword.AMERICANO, - Porcupine.BuiltInKeyword.BLUEBERRY, - Porcupine.BuiltInKeyword.BUMBLEBEE, - Porcupine.BuiltInKeyword.GRAPEFRUIT, - Porcupine.BuiltInKeyword.GRASSHOPPER, - Porcupine.BuiltInKeyword.PICOVOICE, - Porcupine.BuiltInKeyword.PORCUPINE, - Porcupine.BuiltInKeyword.TERMINATOR - }; - - Porcupine p = new Porcupine.Builder() - .setAccessKey(accessKey) - .setKeywords(inputBuiltInKeywords) - .build(appContext); - - File testAudio = new File(testResourcesPath, "audio_samples/multiple_keywords.wav"); - ArrayList detectionResults = processTestAudio(p, testAudio); - p.delete(); - - assertSame(expectedResults.length, detectionResults.size()); - for (int i = 0; i < expectedResults.length; i++) { - Porcupine.BuiltInKeyword expectedKeyword = expectedResults[i]; - assertTrue(detectionResults.get(i) < inputBuiltInKeywords.length); - Porcupine.BuiltInKeyword keywordDetected = inputBuiltInKeywords[detectionResults.get(i)]; - assertSame(expectedKeyword, keywordDetected); - } - } - - @Test - public void testInitWithNonAsciiModelName() throws PorcupineException { - File keywordPath = new File(testResourcesPath, "keyword_files/es/murciƩlago_android.ppn"); - File modelPath = new File(testResourcesPath, "model_files/porcupine_params_es.pv"); - Porcupine p = new Porcupine.Builder() - .setAccessKey(accessKey) - .setKeywordPath(keywordPath.getAbsolutePath()) - .setModelPath(modelPath.getAbsolutePath()) - .build(appContext); - - assertTrue(p.getVersion() != null && !p.getVersion().equals("")); - assertTrue(p.getFrameLength() > 0); - assertTrue(p.getSampleRate() > 0); - - p.delete(); - } - - @Test - public void testErrorStack() { - String[] error = {}; - try { - new Porcupine.Builder() - .setAccessKey("invalid") - .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) - .build(appContext); - } catch (PorcupineException e) { - error = e.getMessageStack(); - } - - assertTrue(0 < error.length); - assertTrue(error.length <= 8); - - try { - new Porcupine.Builder() - .setAccessKey("invalid") - .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) - .build(appContext); - } catch (PorcupineException e) { - for (int i = 0; i < error.length; i++) { - assertEquals(e.getMessageStack()[i], error[i]); - } - } - } - } - - @RunWith(Parameterized.class) - public static class LanguageTests extends BaseTest { - - @Parameterized.Parameter(value = 0) - public String modelFile; - - @Parameterized.Parameter(value = 1) - public String[] keywordFiles; - - @Parameterized.Parameter(value = 2) - public String testAudioFile; - - @Parameterized.Parameter(value = 3) - public int[] expectedResults; - - @Parameterized.Parameters(name = "{0}") - public static Collection initParameters() throws IOException { - String testDataJsonString = getTestDataString(); - - JsonObject testDataJson = JsonParser.parseString(testDataJsonString).getAsJsonObject(); - JsonArray multipleKeywordDataJson = testDataJson.getAsJsonObject("tests").getAsJsonArray("multipleKeyword"); - - List parameters = new ArrayList<>(); - for (int i = 0; i < multipleKeywordDataJson.size(); i++) { - JsonObject testData = multipleKeywordDataJson.get(i).getAsJsonObject(); - String language = testData.get("language").getAsString(); - JsonArray keywords = testData.getAsJsonArray("wakewords"); - JsonArray groundTruthJson = testData.getAsJsonArray("groundTruth"); - - String modelFile = String.format("model_files/porcupine_params_%s.pv", language); - String[] keywordFiles = new String[keywords.size()]; - for (int j = 0; j < keywords.size(); j++) { - String keyword = keywords.get(j).getAsString(); - keywordFiles[j] = String.format("keyword_files/%s/%s_android.ppn", language, keyword); - } - String audioFile = String.format("audio_samples/multiple_keywords_%s.wav", language); - int[] groundTruth = new int[groundTruthJson.size()]; - for (int j = 0; j < groundTruthJson.size(); j++) { - groundTruth[j] = groundTruthJson.get(j).getAsInt(); - } - - if (Objects.equals(language, "en")) { - modelFile = "model_files/porcupine_params.pv"; - audioFile = "audio_samples/multiple_keywords.wav"; - } - - parameters.add(new Object[] { - modelFile, - keywordFiles, - audioFile, - groundTruth - }); - } - - return parameters; - } - - - @Test - public void testProcess() throws Exception { - String modelPath = new File(testResourcesPath, modelFile).getAbsolutePath(); - String[] keywordPaths = new String[keywordFiles.length]; - for (int i = 0; i < keywordFiles.length; i++) { - keywordPaths[i] = new File(testResourcesPath, keywordFiles[i]).getAbsolutePath(); - - } - Porcupine p = new Porcupine.Builder() - .setAccessKey(accessKey) - .setModelPath(modelPath) - .setKeywordPaths(keywordPaths) - .build(appContext); - - assertTrue(p.getVersion() != null && !p.getVersion().equals("")); - assertTrue(p.getFrameLength() > 0); - assertTrue(p.getSampleRate() > 0); - - File testAudio = new File(testResourcesPath, testAudioFile); - ArrayList detectionResults = processTestAudio(p, testAudio); - p.delete(); - - assertSame(expectedResults.length, detectionResults.size()); - for (int i = 0; i < expectedResults.length; i++) { - assertSame(detectionResults.get(i), expectedResults[i]); - } - - p.delete(); - } - } -} diff --git a/binding/android/PorcupineTestApp/porcupine-test-app/src/androidTest/java/ai/picovoice/porcupine/testapp/StandardTests.java b/binding/android/PorcupineTestApp/porcupine-test-app/src/androidTest/java/ai/picovoice/porcupine/testapp/StandardTests.java new file mode 100644 index 000000000..d16c57143 --- /dev/null +++ b/binding/android/PorcupineTestApp/porcupine-test-app/src/androidTest/java/ai/picovoice/porcupine/testapp/StandardTests.java @@ -0,0 +1,338 @@ +/* + Copyright 2025 Picovoice Inc. + + You may not use this file except in compliance with the license. A copy of the license is + located in the "LICENSE" file accompanying this source. + + 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 ai.picovoice.porcupine.testapp; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.ArrayList; + +import ai.picovoice.porcupine.Porcupine; +import ai.picovoice.porcupine.PorcupineException; + + +@RunWith(AndroidJUnit4.class) +public class StandardTests extends BaseTest { + + @Test + public void testInitSuccessWithSingleBuiltIn() throws PorcupineException { + Porcupine p = new Porcupine.Builder() + .setAccessKey(accessKey) + .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) + .build(appContext); + + assertTrue(p.getVersion() != null && !p.getVersion().isEmpty()); + assertTrue(p.getFrameLength() > 0); + assertTrue(p.getSampleRate() > 0); + + p.delete(); + } + + @Test + public void testInitSuccessWithMultipleBuiltIns() throws PorcupineException { + Porcupine.BuiltInKeyword[] inputBuiltInKeywords = new Porcupine.BuiltInKeyword[]{ + Porcupine.BuiltInKeyword.ALEXA, + Porcupine.BuiltInKeyword.GRASSHOPPER, + Porcupine.BuiltInKeyword.PICOVOICE, + Porcupine.BuiltInKeyword.TERMINATOR + }; + + Porcupine p = new Porcupine.Builder() + .setAccessKey(accessKey) + .setKeywords(inputBuiltInKeywords) + .build(appContext); + + assertTrue(p.getVersion() != null && !p.getVersion().isEmpty()); + assertTrue(p.getFrameLength() > 0); + assertTrue(p.getSampleRate() > 0); + + p.delete(); + } + + @Test + public void testInitSuccessWithCustomArguments() throws PorcupineException { + File keywordPath = new File(testResourcesPath, "keyword_files/en/hey_barista_android.ppn"); + File modelPath = new File(testResourcesPath, "model_files/porcupine_params.pv"); + Porcupine p = new Porcupine.Builder() + .setAccessKey(accessKey) + .setModelPath(modelPath.getAbsolutePath()) + .setKeywordPath(keywordPath.getAbsolutePath()) + .setSensitivity(0.25f) + .build(appContext); + + assertTrue(p.getVersion() != null && !p.getVersion().isEmpty()); + assertTrue(p.getFrameLength() > 0); + assertTrue(p.getSampleRate() > 0); + + p.delete(); + } + + @Test + public void testInitSuccessWithMultipleCustomKeywordsAndSensitivities() throws PorcupineException { + File keywordPath = new File(testResourcesPath, "keyword_files/en/hey_barista_android.ppn"); + File keywordPath2 = new File(testResourcesPath, "keyword_files/en/pico_clock_android.ppn"); + String[] keywordPaths = new String[]{keywordPath.getAbsolutePath(), keywordPath2.getAbsolutePath()}; + Porcupine p = new Porcupine.Builder() + .setAccessKey(accessKey) + .setKeywordPaths(keywordPaths) + .setSensitivities(new float[]{0.35f, 0.6f}) + .build(appContext); + + assertTrue(p.getVersion() != null && !p.getVersion().isEmpty()); + assertTrue(p.getFrameLength() > 0); + assertTrue(p.getSampleRate() > 0); + + p.delete(); + } + + @Test + public void testInitFailWithMismatchedLanguage() { + boolean didFail = false; + File keywordPath = new File(testResourcesPath, "keyword_files/de/ananas_android.ppn"); + File modelPath = new File(testResourcesPath, "model_files/porcupine_params.pv"); + try { + new Porcupine.Builder() + .setAccessKey(accessKey) + .setModelPath(modelPath.getAbsolutePath()) + .setKeywordPath(keywordPath.getAbsolutePath()) + .build(appContext); + } catch (PorcupineException e) { + didFail = true; + } + + assertTrue(didFail); + } + + @Test + public void testInitFailWithInvalidModelPath() { + boolean didFail = false; + File modelPath = new File(testResourcesPath, "bad_path/bad_path.pv"); + try { + new Porcupine.Builder() + .setAccessKey(accessKey) + .setModelPath(modelPath.getAbsolutePath()) + .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) + .build(appContext); + } catch (PorcupineException e) { + didFail = true; + } + + assertTrue(didFail); + } + + @Test + public void testInitFailWithInvalidSensitivity() { + boolean didFail = false; + try { + new Porcupine.Builder() + .setAccessKey(accessKey) + .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) + .setSensitivity(10) + .build(appContext); + } catch (PorcupineException e) { + didFail = true; + } + + assertTrue(didFail); + } + + @Test + public void testInitFailWithMismatchedSensitivityCount() { + boolean didFail = false; + try { + new Porcupine.Builder() + .setAccessKey(accessKey) + .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) + .setSensitivities(new float[]{0.4f, 0.8f}) + .build(appContext); + } catch (PorcupineException e) { + didFail = true; + } + + assertTrue(didFail); + } + + @Test + public void testInitFailWithNoKeywords() { + boolean didFail = false; + try { + new Porcupine.Builder() + .setAccessKey(accessKey) + .build(appContext); + } catch (PorcupineException e) { + didFail = true; + } + + assertTrue(didFail); + } + + @Test + public void testInitFailWithInvalidKeywordPath() { + boolean didFail = false; + File keywordPath = new File(testResourcesPath, "bad_path/bad_path.ppn"); + try { + new Porcupine.Builder() + .setAccessKey(accessKey) + .setKeywordPath(keywordPath.getAbsolutePath()) + .build(appContext); + } catch (PorcupineException e) { + didFail = true; + } + + assertTrue(didFail); + } + + @Test + public void testInitFailWithBuiltInAndCustom() { + File keywordPath = new File(testResourcesPath, "keyword_files/en/hey_barista_android.ppn"); + boolean didFail = false; + try { + new Porcupine.Builder() + .setAccessKey(accessKey) + .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) + .setKeywordPath(keywordPath.getAbsolutePath()) + .build(appContext); + } catch (PorcupineException e) { + didFail = true; + } + + assertTrue(didFail); + } + + @Test + public void testInitFailWithWrongKeywordPlatform() { + boolean didFail = false; + File keywordPath = new File(testResourcesPath, "keyword_files/en/alexa_linux.ppn"); + try { + new Porcupine.Builder() + .setAccessKey(accessKey) + .setKeywordPath(keywordPath.getAbsolutePath()) + .build(appContext); + } catch (PorcupineException e) { + didFail = true; + } + + assertTrue(didFail); + } + + @Test + public void testProcSuccessSingleBuiltIn() throws Exception { + Porcupine p = new Porcupine.Builder() + .setAccessKey(accessKey) + .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) + .build(appContext); + + File testAudio = new File(testResourcesPath, "audio_samples/porcupine.wav"); + ArrayList detectionResults = processTestAudio(p, testAudio); + p.delete(); + + assertEquals(1, detectionResults.size()); + assertEquals(0, (int) detectionResults.get(0)); + } + + @Test + public void testProcSuccessMultipleBuiltIn() throws Exception { + Porcupine.BuiltInKeyword[] inputBuiltInKeywords = new Porcupine.BuiltInKeyword[]{ + Porcupine.BuiltInKeyword.ALEXA, + Porcupine.BuiltInKeyword.AMERICANO, + Porcupine.BuiltInKeyword.BLUEBERRY, + Porcupine.BuiltInKeyword.BUMBLEBEE, + Porcupine.BuiltInKeyword.GRAPEFRUIT, + Porcupine.BuiltInKeyword.GRASSHOPPER, + Porcupine.BuiltInKeyword.PICOVOICE, + Porcupine.BuiltInKeyword.PORCUPINE, + Porcupine.BuiltInKeyword.TERMINATOR + }; + + Porcupine.BuiltInKeyword[] expectedResults = new Porcupine.BuiltInKeyword[]{ + Porcupine.BuiltInKeyword.PORCUPINE, + Porcupine.BuiltInKeyword.ALEXA, + Porcupine.BuiltInKeyword.AMERICANO, + Porcupine.BuiltInKeyword.BLUEBERRY, + Porcupine.BuiltInKeyword.BUMBLEBEE, + Porcupine.BuiltInKeyword.GRAPEFRUIT, + Porcupine.BuiltInKeyword.GRASSHOPPER, + Porcupine.BuiltInKeyword.PICOVOICE, + Porcupine.BuiltInKeyword.PORCUPINE, + Porcupine.BuiltInKeyword.TERMINATOR + }; + + Porcupine p = new Porcupine.Builder() + .setAccessKey(accessKey) + .setKeywords(inputBuiltInKeywords) + .build(appContext); + + File testAudio = new File(testResourcesPath, "audio_samples/multiple_keywords.wav"); + ArrayList detectionResults = processTestAudio(p, testAudio); + p.delete(); + + assertSame(expectedResults.length, detectionResults.size()); + for (int i = 0; i < expectedResults.length; i++) { + Porcupine.BuiltInKeyword expectedKeyword = expectedResults[i]; + assertTrue(detectionResults.get(i) < inputBuiltInKeywords.length); + Porcupine.BuiltInKeyword keywordDetected = inputBuiltInKeywords[detectionResults.get(i)]; + assertSame(expectedKeyword, keywordDetected); + } + } + + @Test + public void testInitWithNonAsciiModelName() throws PorcupineException { + File keywordPath = new File(testResourcesPath, "keyword_files/es/murciƩlago_android.ppn"); + File modelPath = new File(testResourcesPath, "model_files/porcupine_params_es.pv"); + Porcupine p = new Porcupine.Builder() + .setAccessKey(accessKey) + .setKeywordPath(keywordPath.getAbsolutePath()) + .setModelPath(modelPath.getAbsolutePath()) + .build(appContext); + + assertTrue(p.getVersion() != null && !p.getVersion().isEmpty()); + assertTrue(p.getFrameLength() > 0); + assertTrue(p.getSampleRate() > 0); + + p.delete(); + } + + @Test + public void testErrorStack() { + String[] error = {}; + try { + new Porcupine.Builder() + .setAccessKey("invalid") + .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) + .build(appContext); + } catch (PorcupineException e) { + error = e.getMessageStack(); + } + + assertTrue(0 < error.length); + assertTrue(error.length <= 8); + + try { + new Porcupine.Builder() + .setAccessKey("invalid") + .setKeyword(Porcupine.BuiltInKeyword.PORCUPINE) + .build(appContext); + } catch (PorcupineException e) { + for (int i = 0; i < error.length; i++) { + assertEquals(e.getMessageStack()[i], error[i]); + } + } + } +}