mirror of
https://github.com/element-hq/element-android
synced 2024-10-15 12:35:22 +00:00
Flow migration: add back some test
This commit is contained in:
parent
8cf5b727e1
commit
a9d192fa39
|
@ -41,7 +41,8 @@ ext.libs = [
|
||||||
jetbrains : [
|
jetbrains : [
|
||||||
'coroutinesCore' : "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutines",
|
'coroutinesCore' : "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutines",
|
||||||
'coroutinesAndroid' : "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutines",
|
'coroutinesAndroid' : "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutines",
|
||||||
'coroutinesRx2' : "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutines"
|
'coroutinesRx2' : "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlinCoroutines",
|
||||||
|
'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines"
|
||||||
],
|
],
|
||||||
androidx : [
|
androidx : [
|
||||||
'appCompat' : "androidx.appcompat:appcompat:1.3.1",
|
'appCompat' : "androidx.appcompat:appcompat:1.3.1",
|
||||||
|
|
|
@ -508,6 +508,7 @@ dependencies {
|
||||||
// Plant Timber tree for test
|
// Plant Timber tree for test
|
||||||
testImplementation libs.tests.timberJunitRule
|
testImplementation libs.tests.timberJunitRule
|
||||||
testImplementation libs.airbnb.mavericksTesting
|
testImplementation libs.airbnb.mavericksTesting
|
||||||
|
testImplementation libs.jetbrains.coroutinesTest
|
||||||
|
|
||||||
// Activate when you want to check for leaks, from time to time.
|
// Activate when you want to check for leaks, from time to time.
|
||||||
//debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
|
//debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
|
||||||
|
@ -521,6 +522,7 @@ dependencies {
|
||||||
androidTestImplementation libs.androidx.espressoIntents
|
androidTestImplementation libs.androidx.espressoIntents
|
||||||
androidTestImplementation libs.tests.kluent
|
androidTestImplementation libs.tests.kluent
|
||||||
androidTestImplementation libs.androidx.coreTesting
|
androidTestImplementation libs.androidx.coreTesting
|
||||||
|
androidTestImplementation libs.jetbrains.coroutinesTest
|
||||||
// Plant Timber tree for test
|
// Plant Timber tree for test
|
||||||
androidTestImplementation libs.tests.timberJunitRule
|
androidTestImplementation libs.tests.timberJunitRule
|
||||||
// "The one who serves a great Espresso"
|
// "The one who serves a great Espresso"
|
||||||
|
|
|
@ -22,6 +22,7 @@ import im.vector.app.test.InstantRxRule
|
||||||
import im.vector.app.test.fakes.FakeSession
|
import im.vector.app.test.fakes.FakeSession
|
||||||
import im.vector.app.test.fakes.FakeStringProvider
|
import im.vector.app.test.fakes.FakeStringProvider
|
||||||
import im.vector.app.test.test
|
import im.vector.app.test.test
|
||||||
|
import kotlinx.coroutines.test.runBlockingTest
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.matrix.android.sdk.api.session.securestorage.IntegrityResult
|
import org.matrix.android.sdk.api.session.securestorage.IntegrityResult
|
||||||
|
@ -41,6 +42,7 @@ class SharedSecureStorageViewModelTest {
|
||||||
|
|
||||||
@get:Rule
|
@get:Rule
|
||||||
val instantRx = InstantRxRule()
|
val instantRx = InstantRxRule()
|
||||||
|
|
||||||
@get:Rule
|
@get:Rule
|
||||||
val mvrxTestRule = MvRxTestRule()
|
val mvrxTestRule = MvRxTestRule()
|
||||||
|
|
||||||
|
@ -50,78 +52,100 @@ class SharedSecureStorageViewModelTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a key info with passphrase when initialising then step is EnterPassphrase`() {
|
fun `given a key info with passphrase when initialising then step is EnterPassphrase`() {
|
||||||
givenKey(KEY_INFO_WITH_PASSPHRASE)
|
runBlockingTest {
|
||||||
|
givenKey(KEY_INFO_WITH_PASSPHRASE)
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
|
viewModel
|
||||||
viewModel.test().assertState(aViewState(
|
.test(this)
|
||||||
hasPassphrase = true,
|
.assertState(aViewState(
|
||||||
step = SharedSecureStorageViewState.Step.EnterPassphrase
|
hasPassphrase = true,
|
||||||
))
|
step = SharedSecureStorageViewState.Step.EnterPassphrase
|
||||||
|
))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a key info without passphrase when initialising then step is EnterKey`() {
|
fun `given a key info without passphrase when initialising then step is EnterKey`() {
|
||||||
givenKey(KEY_INFO_WITHOUT_PASSPHRASE)
|
runBlockingTest {
|
||||||
|
givenKey(KEY_INFO_WITHOUT_PASSPHRASE)
|
||||||
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
|
|
||||||
viewModel.test().assertState(aViewState(
|
viewModel
|
||||||
hasPassphrase = false,
|
.test(this)
|
||||||
step = SharedSecureStorageViewState.Step.EnterKey
|
.assertState(aViewState(
|
||||||
))
|
hasPassphrase = false,
|
||||||
|
step = SharedSecureStorageViewState.Step.EnterKey
|
||||||
|
))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given on EnterKey step when going back then dismisses`() {
|
fun `given on EnterKey step when going back then dismisses`() {
|
||||||
givenKey(KEY_INFO_WITHOUT_PASSPHRASE)
|
runBlockingTest {
|
||||||
|
givenKey(KEY_INFO_WITHOUT_PASSPHRASE)
|
||||||
|
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
val test = viewModel.test()
|
val test = viewModel.test(this)
|
||||||
|
viewModel.handle(SharedSecureStorageAction.Back)
|
||||||
viewModel.handle(SharedSecureStorageAction.Back)
|
test
|
||||||
|
.assertEvents(SharedSecureStorageViewEvent.Dismiss)
|
||||||
test.assertEvents(SharedSecureStorageViewEvent.Dismiss)
|
.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given on passphrase step when using key then step is EnterKey`() {
|
fun `given on passphrase step when using key then step is EnterKey`() {
|
||||||
givenKey(KEY_INFO_WITH_PASSPHRASE)
|
runBlockingTest {
|
||||||
val viewModel = createViewModel()
|
givenKey(KEY_INFO_WITH_PASSPHRASE)
|
||||||
val test = viewModel.test()
|
val viewModel = createViewModel()
|
||||||
|
val test = viewModel.test(this)
|
||||||
|
|
||||||
viewModel.handle(SharedSecureStorageAction.UseKey)
|
viewModel.handle(SharedSecureStorageAction.UseKey)
|
||||||
|
|
||||||
test.assertState(aViewState(
|
test
|
||||||
hasPassphrase = true,
|
.assertState(aViewState(
|
||||||
step = SharedSecureStorageViewState.Step.EnterKey
|
hasPassphrase = true,
|
||||||
))
|
step = SharedSecureStorageViewState.Step.EnterKey
|
||||||
|
))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given a key info with passphrase and on EnterKey step when going back then step is EnterPassphrase`() {
|
fun `given a key info with passphrase and on EnterKey step when going back then step is EnterPassphrase`() {
|
||||||
givenKey(KEY_INFO_WITH_PASSPHRASE)
|
runBlockingTest {
|
||||||
val viewModel = createViewModel()
|
givenKey(KEY_INFO_WITH_PASSPHRASE)
|
||||||
val test = viewModel.test()
|
val viewModel = createViewModel()
|
||||||
|
val test = viewModel.test(this)
|
||||||
|
|
||||||
viewModel.handle(SharedSecureStorageAction.UseKey)
|
viewModel.handle(SharedSecureStorageAction.UseKey)
|
||||||
viewModel.handle(SharedSecureStorageAction.Back)
|
viewModel.handle(SharedSecureStorageAction.Back)
|
||||||
|
|
||||||
test.assertState(aViewState(
|
test
|
||||||
hasPassphrase = true,
|
.assertState(aViewState(
|
||||||
step = SharedSecureStorageViewState.Step.EnterPassphrase
|
hasPassphrase = true,
|
||||||
))
|
step = SharedSecureStorageViewState.Step.EnterPassphrase
|
||||||
|
))
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `given on passphrase step when going back then dismisses`() {
|
fun `given on passphrase step when going back then dismisses`() {
|
||||||
givenKey(KEY_INFO_WITH_PASSPHRASE)
|
runBlockingTest {
|
||||||
val viewModel = createViewModel()
|
givenKey(KEY_INFO_WITH_PASSPHRASE)
|
||||||
val test = viewModel.test()
|
val viewModel = createViewModel()
|
||||||
|
val test = viewModel.test(this)
|
||||||
|
|
||||||
viewModel.handle(SharedSecureStorageAction.Back)
|
viewModel.handle(SharedSecureStorageAction.Back)
|
||||||
|
|
||||||
test.assertEvents(SharedSecureStorageViewEvent.Dismiss)
|
test
|
||||||
|
.assertEvents(SharedSecureStorageViewEvent.Dismiss)
|
||||||
|
.finish()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createViewModel(): SharedSecureStorageViewModel {
|
private fun createViewModel(): SharedSecureStorageViewModel {
|
||||||
|
|
|
@ -20,27 +20,33 @@ import com.airbnb.mvrx.MavericksState
|
||||||
import im.vector.app.core.platform.VectorViewEvents
|
import im.vector.app.core.platform.VectorViewEvents
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.core.platform.VectorViewModelAction
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
import io.reactivex.observers.TestObserver
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import org.amshove.kluent.shouldBeEqualTo
|
import org.amshove.kluent.shouldBeEqualTo
|
||||||
|
|
||||||
fun String.trimIndentOneLine() = trimIndent().replace("\n", "")
|
fun String.trimIndentOneLine() = trimIndent().replace("\n", "")
|
||||||
|
|
||||||
fun <S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents> VectorViewModel<S, VA, VE>.test(): ViewModelTest<S, VE> {
|
fun <S : MavericksState, VA : VectorViewModelAction, VE : VectorViewEvents> VectorViewModel<S, VA, VE>.test(coroutineScope: CoroutineScope): ViewModelTest<S, VE> {
|
||||||
val state = { com.airbnb.mvrx.withState(this) { it } }
|
val state = { com.airbnb.mvrx.withState(this) { it } }
|
||||||
//val viewEvents = viewEvents.stream().test()
|
val viewEvents = viewEvents.stream().test(coroutineScope)
|
||||||
return ViewModelTest(state)
|
return ViewModelTest(state, viewEvents)
|
||||||
}
|
}
|
||||||
|
|
||||||
class ViewModelTest<S, VE>(
|
class ViewModelTest<S, VE>(
|
||||||
val state: () -> S,
|
val state: () -> S,
|
||||||
//val viewEvents: TestObserver<VE>
|
val viewEvents: FlowTestObserver<VE>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun assertEvents(vararg expected: VE) {
|
fun assertEvents(vararg expected: VE): ViewModelTest<S,VE> {
|
||||||
//viewEvents.assertValues(*expected)
|
viewEvents.assertValues(*expected)
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun assertState(expected: S) {
|
fun assertState(expected: S): ViewModelTest<S,VE> {
|
||||||
state() shouldBeEqualTo expected
|
state() shouldBeEqualTo expected
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun finish(){
|
||||||
|
viewEvents.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
53
vector/src/test/java/im/vector/app/test/FlowTestObserver.kt
Normal file
53
vector/src/test/java/im/vector/app/test/FlowTestObserver.kt
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 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.test
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
|
||||||
|
fun <T> Flow<T>.test(scope: CoroutineScope): FlowTestObserver<T> {
|
||||||
|
return FlowTestObserver(scope, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
class FlowTestObserver<T>(
|
||||||
|
scope: CoroutineScope,
|
||||||
|
flow: Flow<T>
|
||||||
|
) {
|
||||||
|
private val values = mutableListOf<T>()
|
||||||
|
private val job: Job = flow
|
||||||
|
.onEach {
|
||||||
|
values.add(it)
|
||||||
|
}.launchIn(scope)
|
||||||
|
|
||||||
|
fun assertNoValues(): FlowTestObserver<T> {
|
||||||
|
assertEquals(emptyList<T>(), this.values)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun assertValues(vararg values: T): FlowTestObserver<T> {
|
||||||
|
assertEquals(values.toList(), this.values)
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun finish() {
|
||||||
|
job.cancel()
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue