Skip to content
Snippets Groups Projects
Unverified Commit f14311af authored by Matthias Urhahn's avatar Matthias Urhahn Committed by GitHub
Browse files
parent b9d71536
No related branches found
No related tags found
No related merge requests found
......@@ -54,4 +54,8 @@ License: Apache-2.0
Files: Corona-Warn-App/src/main/res/font/roboto.ttf
Copyright: 2011 Google Inc.
License: Apache-2.0
Files: Corona-Warn-App/src/test/java/testhelpers/extensions/LiveDataTestUtil.kt
Copyright: 2019 The Android Open Source Project
License: Apache-2.0
\ No newline at end of file
......@@ -75,7 +75,7 @@ class DebugOptionsFragment : Fragment(R.layout.fragment_test_debugoptions), Auto
environmentPubkeyAppconfig.text = "AppConfigPubKey:\n${state.pubKeyAppConfig}"
}
}
vm.environmentChangeEvent.observe2(this) {
vm.environmentStateChange.observe2(this) {
showSnackBar("Environment changed to: $it\nForce stop & restart the app!")
}
}
......
package de.rki.coronawarnapp.test.debugoptions.ui
import androidx.lifecycle.asLiveData
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import de.rki.coronawarnapp.environment.EnvironmentSetup
......@@ -7,25 +8,24 @@ import de.rki.coronawarnapp.environment.EnvironmentSetup.Type.Companion.toEnviro
import de.rki.coronawarnapp.test.debugoptions.ui.EnvironmentState.Companion.toEnvironmentState
import de.rki.coronawarnapp.util.coroutine.DispatcherProvider
import de.rki.coronawarnapp.util.ui.SingleLiveEvent
import de.rki.coronawarnapp.util.ui.smartLiveData
import de.rki.coronawarnapp.util.viewmodel.CWAViewModel
import de.rki.coronawarnapp.util.viewmodel.SimpleCWAViewModelFactory
import kotlinx.coroutines.flow.MutableStateFlow
class DebugOptionsFragmentViewModel @AssistedInject constructor(
private val envSetup: EnvironmentSetup,
dispatcherProvider: DispatcherProvider
) : CWAViewModel(dispatcherProvider = dispatcherProvider) {
val environmentState by smartLiveData {
envSetup.toEnvironmentState()
}
val environmentChangeEvent = SingleLiveEvent<EnvironmentSetup.Type>()
private val environmentStateFlow = MutableStateFlow(envSetup.toEnvironmentState())
val environmentState = environmentStateFlow.asLiveData(context = dispatcherProvider.Default)
val environmentStateChange = SingleLiveEvent<EnvironmentState>()
fun selectEnvironmentTytpe(type: String) {
environmentState.update {
envSetup.currentEnvironment = type.toEnvironmentType()
environmentChangeEvent.postValue(envSetup.currentEnvironment)
envSetup.toEnvironmentState()
envSetup.currentEnvironment = type.toEnvironmentType()
envSetup.toEnvironmentState().let {
environmentStateFlow.value = it
environmentStateChange.postValue(it)
}
}
......
package de.rki.coronawarnapp.util.ui
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
fun <T : Any> ViewModel.smartLiveData(
dispatcher: CoroutineDispatcher = Dispatchers.Default,
liveDataFactory: (ViewModel, CoroutineDispatcher) -> SmartLiveData<T> = { vm, disp ->
SmartLiveData(vm, disp)
},
initAction: suspend () -> T
) = SmartLiveDataProperty(dispatcher, initAction, liveDataFactory)
class SmartLiveDataProperty<T : Any, LV : SmartLiveData<T>>(
private val dispatcher: CoroutineDispatcher = Dispatchers.Default,
private val initialValueProvider: suspend () -> T,
private val liveDataFactory: (ViewModel, CoroutineDispatcher) -> LV
) : ReadOnlyProperty<ViewModel, SmartLiveData<T>> {
private var liveData: SmartLiveData<T>? = null
override fun getValue(
thisRef: ViewModel,
property: KProperty<*>
): SmartLiveData<T> {
liveData?.let {
return@getValue it
}
return liveDataFactory(thisRef, dispatcher).also {
liveData = it
thisRef.viewModelScope.launch(context = dispatcher) {
it.postValue(initialValueProvider())
}
}
}
}
open class SmartLiveData<T : Any>(
private val viewModel: ViewModel,
private val dispatcher: CoroutineDispatcher
) : MutableLiveData<T>() {
fun update(updateAction: (T) -> T) {
observeOnce {
viewModel.viewModelScope.launch(context = dispatcher) {
postValue(updateAction(it))
}
}
}
}
package testhelpers.extensions
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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.
*/
/**
* Thanks to https://github.com/android/architecture-components-samples/blob/master/LiveDataSample/app/src/test/java/com/android/example/livedatabuilder/util/LiveDataTestUtil.kt
*/
package testhelpers.extensions
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import java.util.concurrent.CountDownLatch
......
package de.rki.coronawarnapp.test.debugoptions.ui
import androidx.lifecycle.Observer
import de.rki.coronawarnapp.environment.EnvironmentSetup
import io.kotest.matchers.shouldBe
import io.mockk.MockKAnnotations
import io.mockk.Runs
import io.mockk.every
import io.mockk.impl.annotations.MockK
import io.mockk.just
import io.mockk.mockk
import io.mockk.verify
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import testhelpers.BaseTestInstrumentation
import testhelpers.TestDispatcherProvider
import testhelpers.extensions.CoroutinesTestExtension
import testhelpers.extensions.InstantExecutorExtension
import testhelpers.flakyTest
import testhelpers.extensions.getOrAwaitValue
@ExtendWith(InstantExecutorExtension::class, CoroutinesTestExtension::class)
@ExtendWith(InstantExecutorExtension::class)
class DebugOptionsFragmentViewModelTest : BaseTestInstrumentation() {
@MockK private lateinit var environmentSetup: EnvironmentSetup
......@@ -54,38 +48,15 @@ class DebugOptionsFragmentViewModelTest : BaseTestInstrumentation() {
)
@Test
fun `toggeling the env works`() = flakyTest {
fun `toggeling the env works`() {
currentEnvironment = EnvironmentSetup.Type.DEV
val vm = createViewModel()
val states = mutableListOf<EnvironmentState>()
val observerState = mockk<Observer<EnvironmentState>>()
every { observerState.onChanged(capture(states)) } just Runs
vm.environmentState.observeForever(observerState)
val events = mutableListOf<EnvironmentSetup.Type>()
val observerEvent = mockk<Observer<EnvironmentSetup.Type>>()
every { observerEvent.onChanged(capture(events)) } just Runs
vm.environmentChangeEvent.observeForever(observerEvent)
vm.environmentState.getOrAwaitValue().current shouldBe EnvironmentSetup.Type.DEV
vm.selectEnvironmentTytpe(EnvironmentSetup.Type.DEV.rawKey)
vm.selectEnvironmentTytpe(EnvironmentSetup.Type.WRU_XA.rawKey)
verify(exactly = 3, timeout = 3000) { observerState.onChanged(any()) }
verify(exactly = 2, timeout = 3000) { observerEvent.onChanged(any()) }
states[0].apply {
current shouldBe EnvironmentSetup.Type.DEV
}
states[1].apply {
current shouldBe EnvironmentSetup.Type.DEV
}
events[0] shouldBe EnvironmentSetup.Type.DEV
vm.environmentState.getOrAwaitValue().current shouldBe EnvironmentSetup.Type.DEV
states[2].apply {
current shouldBe EnvironmentSetup.Type.WRU_XA
}
events[1] shouldBe EnvironmentSetup.Type.WRU_XA
vm.selectEnvironmentTytpe(EnvironmentSetup.Type.WRU_XA.rawKey)
vm.environmentState.getOrAwaitValue().current shouldBe EnvironmentSetup.Type.WRU_XA
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment