diff --git a/features/rageshake/build.gradle.kts b/features/rageshake/build.gradle.kts index ecb333289b..d1aee8d989 100644 --- a/features/rageshake/build.gradle.kts +++ b/features/rageshake/build.gradle.kts @@ -45,6 +45,13 @@ dependencies { implementation(libs.coil) implementation(libs.coil.compose) ksp(libs.showkase.processor) + testImplementation(libs.test.junit) + testImplementation(libs.coroutines.test) + testImplementation(libs.molecule.runtime) + testImplementation(libs.test.truth) + testImplementation(libs.test.turbine) + testImplementation(projects.libraries.matrixtest) + androidTestImplementation(libs.test.junitext) } diff --git a/features/rageshake/src/test/kotlin/io/element/android/features/login/ExampleUnitTest.kt b/features/rageshake/src/test/kotlin/io/element/android/features/rageshake/preferences/FakeRageShake.kt similarity index 51% rename from features/rageshake/src/test/kotlin/io/element/android/features/login/ExampleUnitTest.kt rename to features/rageshake/src/test/kotlin/io/element/android/features/rageshake/preferences/FakeRageShake.kt index ee6363e624..6d0669cd7c 100644 --- a/features/rageshake/src/test/kotlin/io/element/android/features/login/ExampleUnitTest.kt +++ b/features/rageshake/src/test/kotlin/io/element/android/features/rageshake/preferences/FakeRageShake.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright (c) 2023 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. @@ -14,19 +14,27 @@ * limitations under the License. */ -package io.element.android.features.login +package io.element.android.features.rageshake.preferences -import org.junit.Assert.assertEquals -import org.junit.Test +import io.element.android.features.rageshake.rageshake.RageShake -/** - * Example local unit test, which will execute on the development machine (host). - * - * See [testing documentation](http://d.android.com/tools/testing). - */ -class ExampleUnitTest { - @Test - fun addition_isCorrect() { - assertEquals(4, 2 + 2) +const val A_SENSITIVITY = 1f + +class FakeRageShake( + private var isAvailableValue: Boolean = true +) : RageShake { + + override fun isAvailable() = isAvailableValue + + override fun start(sensitivity: Float) { + } + + override fun stop() { + } + + override fun setSensitivity(sensitivity: Float) { + } + + override fun setInterceptor(interceptor: (() -> Unit)?) { } } diff --git a/features/rageshake/src/test/kotlin/io/element/android/features/rageshake/preferences/FakeRageshakeDataStore.kt b/features/rageshake/src/test/kotlin/io/element/android/features/rageshake/preferences/FakeRageshakeDataStore.kt new file mode 100644 index 0000000000..22c4ae4d4d --- /dev/null +++ b/features/rageshake/src/test/kotlin/io/element/android/features/rageshake/preferences/FakeRageshakeDataStore.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 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 io.element.android.features.rageshake.preferences + +import io.element.android.features.rageshake.rageshake.RageshakeDataStore +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow + +class FakeRageshakeDataStore( + isEnabled: Boolean = true, + sensitivity: Float = A_SENSITIVITY, +) : RageshakeDataStore { + + private val isEnabledFlow = MutableStateFlow(isEnabled) + override fun isEnabled(): Flow = isEnabledFlow + + override suspend fun setIsEnabled(isEnabled: Boolean) { + isEnabledFlow.value = isEnabled + } + + private val sensitivityFlow = MutableStateFlow(sensitivity) + override fun sensitivity(): Flow = sensitivityFlow + + override suspend fun setSensitivity(sensitivity: Float) { + sensitivityFlow.value = sensitivity + } + + override suspend fun reset() = Unit +} diff --git a/features/rageshake/src/test/kotlin/io/element/android/features/rageshake/preferences/RageshakePreferencesPresenterTest.kt b/features/rageshake/src/test/kotlin/io/element/android/features/rageshake/preferences/RageshakePreferencesPresenterTest.kt new file mode 100644 index 0000000000..17a46e8da6 --- /dev/null +++ b/features/rageshake/src/test/kotlin/io/element/android/features/rageshake/preferences/RageshakePreferencesPresenterTest.kt @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2023 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. + */ + +@file:OptIn(ExperimentalCoroutinesApi::class) + +package io.element.android.features.rageshake.preferences + +import app.cash.molecule.RecompositionClock +import app.cash.molecule.moleculeFlow +import app.cash.turbine.test +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.runTest +import org.junit.Test + +class RageshakePreferencesPresenterTest { + @Test + fun `present - initial state available`() = runTest { + val presenter = RageshakePreferencesPresenter( + FakeRageShake(isAvailableValue = true), + FakeRageshakeDataStore(isEnabled = true) + ) + moleculeFlow(RecompositionClock.Immediate) { + presenter.present() + }.test { + skipItems(1) + val initialState = awaitItem() + assertThat(initialState.isSupported).isTrue() + assertThat(initialState.isEnabled).isTrue() + } + } + + @Test + fun `present - initial state not available`() = runTest { + val presenter = RageshakePreferencesPresenter( + FakeRageShake(isAvailableValue = false), + FakeRageshakeDataStore(isEnabled = true) + ) + moleculeFlow(RecompositionClock.Immediate) { + presenter.present() + }.test { + skipItems(1) + val initialState = awaitItem() + assertThat(initialState.isSupported).isFalse() + assertThat(initialState.isEnabled).isTrue() + } + } + + @Test + fun `present - enable and disable`() = runTest { + val presenter = RageshakePreferencesPresenter( + FakeRageShake(isAvailableValue = true), + FakeRageshakeDataStore(isEnabled = true) + ) + moleculeFlow(RecompositionClock.Immediate) { + presenter.present() + }.test { + skipItems(1) + val initialState = awaitItem() + assertThat(initialState.isEnabled).isTrue() + initialState.eventSink.invoke(RageshakePreferencesEvents.SetIsEnabled(false)) + assertThat(awaitItem().isEnabled).isFalse() + initialState.eventSink.invoke(RageshakePreferencesEvents.SetIsEnabled(true)) + assertThat(awaitItem().isEnabled).isTrue() + } + } + + @Test + fun `present - set sensitivity`() = runTest { + val presenter = RageshakePreferencesPresenter( + FakeRageShake(isAvailableValue = true), + FakeRageshakeDataStore(isEnabled = true) + ) + moleculeFlow(RecompositionClock.Immediate) { + presenter.present() + }.test { + skipItems(1) + val initialState = awaitItem() + assertThat(initialState.sensitivity).isEqualTo(A_SENSITIVITY) + initialState.eventSink.invoke(RageshakePreferencesEvents.SetSensitivity(A_SENSITIVITY + 1f)) + assertThat(awaitItem().sensitivity).isEqualTo(A_SENSITIVITY + 1f) + } + } +} +