From 64334c343719c0849ce70fd4e0fa99ed860e1836 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Mart=C3=ADn?= Date: Fri, 10 Jun 2022 09:51:20 +0200 Subject: [PATCH] Add some tests --- dependencies.gradle | 2 +- vector/build.gradle | 1 + .../vector/app/AndroidVersionTestOverrider.kt | 46 +++++++++++ .../app/features/voice/VoiceRecorderLTests.kt | 79 +++++++++++++++++++ .../voice/VoiceRecorderProviderTests.kt | 47 +++++++++++ .../app/features/voice/VoiceRecorderQTests.kt | 78 ++++++++++++++++++ .../app/features/voice/VoiceRecorderTests.kt | 56 +++++++++++++ .../features/voice/AbstractVoiceRecorder.kt | 2 +- 8 files changed, 309 insertions(+), 2 deletions(-) create mode 100644 vector/src/androidTest/java/im/vector/app/AndroidVersionTestOverrider.kt create mode 100644 vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderLTests.kt create mode 100644 vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt create mode 100644 vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderQTests.kt create mode 100644 vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderTests.kt diff --git a/dependencies.gradle b/dependencies.gradle index 272a26886b..fdc2c5d941 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -29,7 +29,7 @@ def jjwt = "0.11.5" def vanniktechEmoji = "0.15.0" // Testing -def mockk = "1.12.4" +def mockk = "1.12.3" def espresso = "3.4.0" def androidxTest = "1.4.0" def androidxOrchestrator = "1.4.1" diff --git a/vector/build.gradle b/vector/build.gradle index 7aa7ba7366..256ffd5b1f 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -547,5 +547,6 @@ dependencies { androidTestImplementation('com.adevinta.android:barista:4.2.0') { exclude group: 'org.jetbrains.kotlin' } + androidTestImplementation libs.mockk.mockkAndroid androidTestUtil libs.androidx.orchestrator } diff --git a/vector/src/androidTest/java/im/vector/app/AndroidVersionTestOverrider.kt b/vector/src/androidTest/java/im/vector/app/AndroidVersionTestOverrider.kt new file mode 100644 index 0000000000..97333b7c98 --- /dev/null +++ b/vector/src/androidTest/java/im/vector/app/AndroidVersionTestOverrider.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * 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 im.vector.app + +import android.os.Build +import java.lang.reflect.Field + +/** + * Used to override [Build.VERSION.SDK_INT]. Ideally an interface should be used instead, but that approach forces us to either add suppress lint annotations + * and potentially miss an API version issue or write a custom lint rule, which seems like an overkill. + */ +object AndroidVersionTestOverrider { + + private var initialValue: Int? = null + + fun override(newVersion: Int) { + if (initialValue == null) { + initialValue = Build.VERSION.SDK_INT + } + val field = Build.VERSION::class.java.getField("SDK_INT") + setStaticField(field, newVersion) + } + + fun restore() { + initialValue?.let { override(it) } + } + + private fun setStaticField(field: Field, value: Any) { + field.isAccessible = true + field.set(null, value) + } +} diff --git a/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderLTests.kt b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderLTests.kt new file mode 100644 index 0000000000..a7cc252fb7 --- /dev/null +++ b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderLTests.kt @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * 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 im.vector.app.features.voice + +import android.Manifest +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.GrantPermissionRule +import io.mockk.spyk +import io.mockk.verify +import kotlinx.coroutines.Dispatchers +import org.amshove.kluent.shouldBeNull +import org.amshove.kluent.shouldExist +import org.amshove.kluent.shouldNotBeNull +import org.amshove.kluent.shouldNotExist +import org.junit.Rule +import org.junit.Test +import java.io.File + +class VoiceRecorderLTests { + + @get:Rule + val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(Manifest.permission.RECORD_AUDIO) + + private val context = InstrumentationRegistry.getInstrumentation().targetContext + private val recorder = spyk(VoiceRecorderL(context, Dispatchers.IO)) + + @Test + fun startRecordCreatesOggFile() = with(recorder) { + getVoiceMessageFile().shouldBeNull() + + startRecord("some_room_id") + + getVoiceMessageFile().shouldNotBeNullAndExist() + + stopRecord() + } + + @Test + fun stopRecordKeepsFile() = with(recorder) { + getVoiceMessageFile().shouldBeNull() + + startRecord("some_room_id") + stopRecord() + + getVoiceMessageFile().shouldNotBeNullAndExist() + } + + @Test + fun cancelRecordRemovesFileAfterStopping() = with(recorder) { + startRecord("some_room_id") + val file = recorder.getVoiceMessageFile() + file.shouldNotBeNullAndExist() + + cancelRecord() + + verify { stopRecord() } + getVoiceMessageFile().shouldBeNull() + file!!.shouldNotExist() + } +} + +private fun File?.shouldNotBeNullAndExist() { + shouldNotBeNull() + shouldExist() +} diff --git a/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt new file mode 100644 index 0000000000..c7105b613f --- /dev/null +++ b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * 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 im.vector.app.features.voice + +import android.os.Build +import androidx.test.platform.app.InstrumentationRegistry +import im.vector.app.AndroidVersionTestOverrider +import org.amshove.kluent.shouldBeInstanceOf +import org.junit.After +import org.junit.Test + +class VoiceRecorderProviderTests { + + private val context = InstrumentationRegistry.getInstrumentation().targetContext + private val provider = VoiceRecorderProvider(context) + + @After + fun tearDown() { + AndroidVersionTestOverrider.restore() + } + + @Test + fun provideVoiceRecorderOnAndroidQReturnsQRecorder() { + AndroidVersionTestOverrider.override(Build.VERSION_CODES.Q) + provider.provideVoiceRecorder().shouldBeInstanceOf(VoiceRecorderQ::class) + } + + @Test + fun provideVoiceRecorderOnOlderAndroidVersionReturnsLRecorder() { + AndroidVersionTestOverrider.override(Build.VERSION_CODES.LOLLIPOP) + provider.provideVoiceRecorder().shouldBeInstanceOf(VoiceRecorderL::class) + } +} diff --git a/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderQTests.kt b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderQTests.kt new file mode 100644 index 0000000000..395c1f21d9 --- /dev/null +++ b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderQTests.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * 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 im.vector.app.features.voice + +import android.Manifest +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.rule.GrantPermissionRule +import io.mockk.spyk +import io.mockk.verify +import org.amshove.kluent.shouldBeNull +import org.amshove.kluent.shouldExist +import org.amshove.kluent.shouldNotBeNull +import org.amshove.kluent.shouldNotExist +import org.junit.Rule +import org.junit.Test +import java.io.File + +class VoiceRecorderQTests { + + @get:Rule + val grantPermissionRule: GrantPermissionRule = GrantPermissionRule.grant(Manifest.permission.RECORD_AUDIO) + + private val context = InstrumentationRegistry.getInstrumentation().targetContext + private val recorder = spyk(VoiceRecorderQ(context)) + + @Test + fun startRecordCreatesOggFile() = with(recorder) { + getVoiceMessageFile().shouldBeNull() + + startRecord("some_room_id") + + getVoiceMessageFile().shouldNotBeNullAndExist() + + stopRecord() + } + + @Test + fun stopRecordKeepsFile() = with(recorder) { + getVoiceMessageFile().shouldBeNull() + + startRecord("some_room_id") + stopRecord() + + getVoiceMessageFile().shouldNotBeNullAndExist() + } + + @Test + fun cancelRecordRemovesFileAfterStopping() = with(recorder) { + startRecord("some_room_id") + val file = recorder.getVoiceMessageFile() + file.shouldNotBeNullAndExist() + + cancelRecord() + + verify { stopRecord() } + getVoiceMessageFile().shouldBeNull() + file!!.shouldNotExist() + } +} + +private fun File?.shouldNotBeNullAndExist() { + shouldNotBeNull() + shouldExist() +} diff --git a/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderTests.kt b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderTests.kt new file mode 100644 index 0000000000..7feeff83cb --- /dev/null +++ b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderTests.kt @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * 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 im.vector.app.features.voice + +import android.net.Uri +import androidx.test.platform.app.InstrumentationRegistry +import kotlinx.coroutines.Dispatchers +import org.amshove.kluent.shouldBeEqualTo +import org.amshove.kluent.shouldExist +import org.junit.After +import org.junit.Test +import org.matrix.android.sdk.api.session.content.ContentAttachmentData +import java.io.File + +class VoiceRecorderTests { + + private val context = InstrumentationRegistry.getInstrumentation().targetContext + private val voiceRecorder = VoiceRecorderL(context, Dispatchers.IO) + private val audioDirectory = File(context.cacheDir, "voice_records") + + @After + fun tearDown() { + audioDirectory.deleteRecursively() + } + + @Test + fun ensureAudioDirectoryCreatesIt() { + voiceRecorder.ensureAudioDirectory(context) + audioDirectory.shouldExist() + } + + @Test + fun findVoiceFileSearchesInDirectory() { + val filename = "someFile.ogg" + val attachment = ContentAttachmentData( + queryUri = Uri.parse(filename), + mimeType = "ogg", + type = ContentAttachmentData.Type.AUDIO + ) + attachment.findVoiceFile(audioDirectory) shouldBeEqualTo File(audioDirectory, filename) + } +} diff --git a/vector/src/main/java/im/vector/app/features/voice/AbstractVoiceRecorder.kt b/vector/src/main/java/im/vector/app/features/voice/AbstractVoiceRecorder.kt index 13b8149f83..91eb371f42 100644 --- a/vector/src/main/java/im/vector/app/features/voice/AbstractVoiceRecorder.kt +++ b/vector/src/main/java/im/vector/app/features/voice/AbstractVoiceRecorder.kt @@ -27,7 +27,7 @@ import java.util.UUID abstract class AbstractVoiceRecorder( private val context: Context, - internal val filenameExt: String + private val filenameExt: String, ) : VoiceRecorder { private val outputDirectory: File by lazy { ensureAudioDirectory(context) }