diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigProvider.kt index 47810d4506d7d8d10215e7d5991730b99325e99c..8ee5e894584a3a07e051c950e946ca9ebbf5b548 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigProvider.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/appconfig/AppConfigProvider.kt @@ -74,7 +74,8 @@ class AppConfigProvider @Inject constructor( } return newConfigParsed?.also { - Timber.v("Saving new valid config.") + Timber.d("Saving new valid config.") + Timber.v("New Config.supportedCountries: %s", it.supportedCountriesList) configStorage.appConfigRaw = newConfigRaw } } @@ -99,12 +100,32 @@ class AppConfigProvider @Inject constructor( Timber.w("No new config available, using last valid.") getFallback() } + }.performSanityChecks() + + private fun ApplicationConfiguration.performSanityChecks(): ApplicationConfiguration { + var sanityChecked = this + + if (sanityChecked.supportedCountriesList == null) { + sanityChecked = sanityChecked.toNewConfig { + clearSupportedCountries() + addAllSupportedCountries(emptyList<String>()) + } + } + + val countryCheck = sanityChecked.supportedCountriesList + if (countryCheck.size == 1 && !VALID_CC.matches(countryCheck.single())) { + Timber.w("Invalid country data, clearing. (%s)", this.supportedCountriesList) + sanityChecked = sanityChecked.toNewConfig { + clearSupportedCountries() + } + } + return sanityChecked } companion object { - private val TAG = AppConfigProvider::class.java.simpleName - + private val VALID_CC = "^([A-Z]{2,3})$".toRegex() private const val EXPORT_BINARY_FILE_NAME = "export.bin" private const val EXPORT_SIGNATURE_FILE_NAME = "export.sig" + private val TAG = AppConfigProvider::class.java.simpleName } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt index 4c9e23a424d0248e9107d3d1ce6462ed7b45edf9..e82f912b257d2afee323163116b35937e82bf209 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationService.kt @@ -2,28 +2,11 @@ package de.rki.coronawarnapp.service.applicationconfiguration import com.google.android.gms.nearby.exposurenotification.ExposureConfiguration import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass.ApplicationConfiguration -import de.rki.coronawarnapp.util.CWADebug import de.rki.coronawarnapp.util.di.AppInjector object ApplicationConfigurationService { suspend fun asyncRetrieveApplicationConfiguration(): ApplicationConfiguration { - return AppInjector.component.appConfigProvider.getAppConfig().let { - if (CWADebug.isDebugBuildOrMode) { - // TODO: THIS IS A MOCK -> Remove after Backend is providing this information. - it.toBuilder() - .clearSupportedCountries() - .addAllSupportedCountries( - listOf( - "DE", "UK", "FR", "IT", "ES", "PL", "RO", "NL", - "BE", "CZ", "SE", "PT", "HU", "AT", "CH", "BG", "DK", "FI", "SK", - "NO", "IE", "HR", "SI", "LT", "LV", "EE", "CY", "LU", "MT", "IS" - ) - ) - .build() - } else { - it - } - } + return AppInjector.component.appConfigProvider.getAppConfig() } suspend fun asyncRetrieveExposureConfiguration(): ExposureConfiguration = diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/interoperability/InteroperabilityRepository.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/interoperability/InteroperabilityRepository.kt index 4a3e769030a34a04fcf9e92779292870ce2bf361..90768259c610867b8e66e7a53e00bb9e25bb501f 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/interoperability/InteroperabilityRepository.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/storage/interoperability/InteroperabilityRepository.kt @@ -3,8 +3,9 @@ package de.rki.coronawarnapp.storage.interoperability import android.text.TextUtils import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations -import de.rki.coronawarnapp.service.applicationconfiguration.ApplicationConfigurationService +import de.rki.coronawarnapp.appconfig.AppConfigProvider import de.rki.coronawarnapp.storage.LocalData +import de.rki.coronawarnapp.ui.Country import kotlinx.coroutines.runBlocking import timber.log.Timber import java.util.Locale @@ -12,13 +13,15 @@ import javax.inject.Inject import javax.inject.Singleton @Singleton -class InteroperabilityRepository @Inject constructor() { +class InteroperabilityRepository @Inject constructor( + private val appConfigProvider: AppConfigProvider +) { fun saveInteroperabilityUsed() { LocalData.isInteroperabilityShownAtLeastOnce = true } - private val _countryList: MutableLiveData<List<String>> = MutableLiveData(listOf()) + private val _countryList: MutableLiveData<List<Country>> = MutableLiveData(listOf()) val countryList = Transformations.distinctUntilChanged(_countryList) init { @@ -29,14 +32,18 @@ class InteroperabilityRepository @Inject constructor() { * Gets all countries from @see ApplicationConfigurationService.asyncRetrieveApplicationConfiguration * Also changes every country code to lower case */ - fun getAllCountries() { runBlocking { try { - val countries = - ApplicationConfigurationService.asyncRetrieveApplicationConfiguration() - .supportedCountriesList - ?.map { it.toLowerCase(Locale.ROOT) } ?: listOf() + val countries = appConfigProvider.getAppConfig() + .supportedCountriesList + .mapNotNull { rawCode -> + val countryCode = rawCode.toLowerCase(Locale.ROOT) + + val mappedCountry = Country.values().singleOrNull { it.code == countryCode } + if (mappedCountry == null) Timber.e("Unknown countrycode: %s", rawCode) + mappedCountry + } _countryList.postValue(countries) Timber.d("Country list: ${TextUtils.join(System.lineSeparator(), countries)}") } catch (e: Exception) { diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/Country.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/Country.kt new file mode 100644 index 0000000000000000000000000000000000000000..2c22c8b002551f81783c5690ba7636e090db55c7 --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/Country.kt @@ -0,0 +1,44 @@ +package de.rki.coronawarnapp.ui + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import de.rki.coronawarnapp.R + +enum class Country( + val code: String, + @StringRes val labelRes: Int, + @DrawableRes val iconRes: Int +) { + AT("at", R.string.country_name_at, R.drawable.ic_country_at), + BE("be", R.string.country_name_be, R.drawable.ic_country_be), + BG("bg", R.string.country_name_bg, R.drawable.ic_country_bg), + CH("ch", R.string.country_name_ch, R.drawable.ic_country_ch), + CY("cy", R.string.country_name_cy, R.drawable.ic_country_cy), + CZ("cz", R.string.country_name_cz, R.drawable.ic_country_cz), + DE("de", R.string.country_name_de, R.drawable.ic_country_de), + DK("dk", R.string.country_name_dk, R.drawable.ic_country_dk), + EE("ee", R.string.country_name_ee, R.drawable.ic_country_ee), + ES("es", R.string.country_name_es, R.drawable.ic_country_es), + FI("fi", R.string.country_name_fi, R.drawable.ic_country_fi), + FR("fr", R.string.country_name_fr, R.drawable.ic_country_fr), + UK("uk", R.string.country_name_uk, R.drawable.ic_country_uk), + GR("gr", R.string.country_name_gr, R.drawable.ic_country_gr), + HR("hr", R.string.country_name_hr, R.drawable.ic_country_hr), + HU("hu", R.string.country_name_hu, R.drawable.ic_country_hu), + IE("ie", R.string.country_name_ie, R.drawable.ic_country_ie), + IS("is", R.string.country_name_is, R.drawable.ic_country_is), + IT("it", R.string.country_name_it, R.drawable.ic_country_it), + LI("li", R.string.country_name_li, R.drawable.ic_country_li), + LT("lt", R.string.country_name_lt, R.drawable.ic_country_lt), + LU("lu", R.string.country_name_lu, R.drawable.ic_country_lu), + LV("lv", R.string.country_name_lv, R.drawable.ic_country_lv), + MT("mt", R.string.country_name_mt, R.drawable.ic_country_mt), + NL("nl", R.string.country_name_nl, R.drawable.ic_country_nl), + NO("no", R.string.country_name_no, R.drawable.ic_country_no), + PL("pl", R.string.country_name_pl, R.drawable.ic_country_pl), + PT("pt", R.string.country_name_pt, R.drawable.ic_country_pt), + RO("ro", R.string.country_name_ro, R.drawable.ic_country_ro), + SE("se", R.string.country_name_se, R.drawable.ic_country_se), + SI("si", R.string.country_name_si, R.drawable.ic_country_si), + SK("sk", R.string.country_name_sk, R.drawable.ic_country_sk) +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/CountryList.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/CountryList.kt index 48325e2631b2f3b628d01eeef6b36c4a4d8417aa..a97986690a52f7aa4223a34e29d7a7c3f33adfb0 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/CountryList.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/view/CountryList.kt @@ -2,23 +2,19 @@ package de.rki.coronawarnapp.ui.view import android.content.Context import android.util.AttributeSet -import android.view.View import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView -import androidx.core.content.res.ResourcesCompat import de.rki.coronawarnapp.R +import de.rki.coronawarnapp.ui.Country import java.text.Collator -import java.util.Locale class CountryList(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) { - private var _list: List<String>? = null - var list: List<String>? - get() { - return _list?.map { it.toLowerCase(Locale.ROOT) } - } + private var _list: List<Country>? = null + var list: List<Country>? + get() = _list set(value) { _list = value buildList() @@ -34,49 +30,19 @@ class CountryList(context: Context, attrs: AttributeSet) : private fun buildList() { this.removeAllViews() list - ?.map { countryCode -> - val countryNameResourceId = context.resources.getIdentifier( - "country_name_$countryCode", - "string", - context.packageName - ) - Pair(countryCode, context.getString(countryNameResourceId)) + ?.map { country -> + context.getString(country.labelRes) to country.iconRes + } + ?.sortedWith { a, b -> + Collator.getInstance().compare(a.first, b.first) } - ?.sortedWith(Comparator { a, b -> - Collator.getInstance().compare(a.second, b.second) - }) - ?.forEachIndexed { index, country -> + ?.forEachIndexed { index, (label, iconRes) -> inflate(context, R.layout.view_country_list_entry, this) val child = this.getChildAt(index) - this.setEntryValues(child, country.first, country.second) + child.apply { + findViewById<ImageView>(R.id.country_list_entry_image).setImageResource(iconRes) + findViewById<TextView>(R.id.country_list_entry_label).text = label + } } } - - /** - * Sets the values of the views of each entry in the list - * @param entry the view of the current entry - * @param countryCode needed to determine which country is used for the current entry - * @param selected sets the status of the switch for the current entry - */ - private fun setEntryValues( - entry: View, - countryCode: String, - countryName: String - ) { - - // get drawable (flag of country) resource if dynamically based on country code - val countryFlagImageDrawableId = context.resources.getIdentifier( - "ic_country_$countryCode", - "drawable", - context.packageName - ) - - val countryFlagDrawable = ResourcesCompat - .getDrawable(context.resources, countryFlagImageDrawableId, null) - - entry.findViewById<ImageView>(R.id.country_list_entry_image) - .setImageDrawable(countryFlagDrawable) - - entry.findViewById<TextView>(R.id.country_list_entry_label).text = countryName - } } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt index 800dcc8213426cedd29bfb9c435f3775c53a2cd2..5f2c6cbdaa6a8bde5fc4b1fbba7b8e0766eccde5 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/viewmodel/SubmissionViewModel.kt @@ -22,6 +22,7 @@ import de.rki.coronawarnapp.ui.submission.SymptomCalendarEvent import de.rki.coronawarnapp.ui.submission.SymptomIntroductionEvent import de.rki.coronawarnapp.util.DeviceUIState import de.rki.coronawarnapp.util.Event +import de.rki.coronawarnapp.util.di.AppInjector import kotlinx.coroutines.launch import org.joda.time.LocalDate import timber.log.Timber @@ -38,7 +39,8 @@ class SubmissionViewModel : ViewModel() { private val _submissionState = MutableLiveData(ApiRequestState.IDLE) private val _submissionError = MutableLiveData<Event<CwaWebException>>(null) - private val interoperabilityRepository = InteroperabilityRepository() + private val interoperabilityRepository: InteroperabilityRepository + get() = AppInjector.component.interoperabilityRepository val scanStatus: LiveData<Event<ScanStatus>> = _scanStatus @@ -63,7 +65,10 @@ class SubmissionViewModel : ViewModel() { val symptomIndication = MutableLiveData<Symptoms.Indication?>() val symptomStart = MutableLiveData<Symptoms.StartOf?>() - val countryList = MutableLiveData(interoperabilityRepository.countryList) + + val countryList by lazy { + MutableLiveData(interoperabilityRepository.countryList) + } fun initSymptoms() { symptomIndication.postValue(null) diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt index 7f90b2cf5494101e1063517762db380aa86e1208..ff04498335e1bdcdf5e2839730798a2d68e86534 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/util/di/ApplicationComponent.kt @@ -20,6 +20,7 @@ import de.rki.coronawarnapp.receiver.ReceiverBinder import de.rki.coronawarnapp.risk.RiskModule import de.rki.coronawarnapp.service.ServiceBinder import de.rki.coronawarnapp.storage.SettingsRepository +import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository import de.rki.coronawarnapp.submission.SubmissionModule import de.rki.coronawarnapp.transaction.RetrieveDiagnosisInjectionHelper import de.rki.coronawarnapp.transaction.RiskLevelInjectionHelper @@ -78,6 +79,8 @@ interface ApplicationComponent : AndroidInjector<CoronaWarnApplication> { val playbook: Playbook + val interoperabilityRepository: InteroperabilityRepository + @Component.Factory interface Factory { fun create(@BindsInstance app: CoronaWarnApplication): ApplicationComponent diff --git a/Corona-Warn-App/src/main/res/layout/fragment_interoperability_configuration.xml b/Corona-Warn-App/src/main/res/layout/fragment_interoperability_configuration.xml index a0d7a6b251923cbb99f6534e2600464db802e9c2..5061f03075ee26981a75e575ffb8bfa1b7d6d7ff 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_interoperability_configuration.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_interoperability_configuration.xml @@ -5,7 +5,7 @@ <data> <variable name="countryData" - type="java.util.List<String>" /> + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> </data> <androidx.constraintlayout.widget.ConstraintLayout diff --git a/Corona-Warn-App/src/main/res/layout/fragment_onboarding_delta_interoperability.xml b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_delta_interoperability.xml index 7b1ec16ca64f262d1a3883403456c3d862d42347..c496d23825b7e39f4018e6329be861e92fafa49a 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_onboarding_delta_interoperability.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_delta_interoperability.xml @@ -6,7 +6,7 @@ <variable name="countryData" - type="java.util.List<String>" /> + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> </data> <androidx.constraintlayout.widget.ConstraintLayout diff --git a/Corona-Warn-App/src/main/res/layout/fragment_onboarding_tracing.xml b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_tracing.xml index 5fa04241d229ffcde75f028ab85f7423dd2fd036..07f2ea6b9343f7a9d90235899e4e6fecea6a7e23 100644 --- a/Corona-Warn-App/src/main/res/layout/fragment_onboarding_tracing.xml +++ b/Corona-Warn-App/src/main/res/layout/fragment_onboarding_tracing.xml @@ -5,7 +5,7 @@ <data> <variable name="countryData" - type="java.util.List<String>" /> + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> </data> <androidx.constraintlayout.widget.ConstraintLayout diff --git a/Corona-Warn-App/src/main/res/layout/include_interop_list_participating_countries_overview.xml b/Corona-Warn-App/src/main/res/layout/include_interop_list_participating_countries_overview.xml index 4f5896f4d1adb08e8952d9b0ca3bee8eef2a260b..f6142d91d2b25a4ddeb6c664fbf4d346b6f046dc 100644 --- a/Corona-Warn-App/src/main/res/layout/include_interop_list_participating_countries_overview.xml +++ b/Corona-Warn-App/src/main/res/layout/include_interop_list_participating_countries_overview.xml @@ -8,7 +8,7 @@ <variable name="countryData" - type="java.util.List<String>" /> + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> <variable name="countryListTitle" diff --git a/Corona-Warn-App/src/main/res/layout/include_interoperability.xml b/Corona-Warn-App/src/main/res/layout/include_interoperability.xml index b69a0dd4afd34d42f75d27123499700695df298c..b1b874c9a2a040d353f14cc8016eff62a5b1d4e3 100644 --- a/Corona-Warn-App/src/main/res/layout/include_interoperability.xml +++ b/Corona-Warn-App/src/main/res/layout/include_interoperability.xml @@ -11,7 +11,7 @@ <variable name="countryData" - type="java.util.List<String>" /> + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> <variable name="title" diff --git a/Corona-Warn-App/src/main/res/layout/include_onboarding.xml b/Corona-Warn-App/src/main/res/layout/include_onboarding.xml index f5c0341a4983e04552f1f8ff7722e6ea633b3d15..148009f3a9db6bd82531d73a62124e6d8be92524 100644 --- a/Corona-Warn-App/src/main/res/layout/include_onboarding.xml +++ b/Corona-Warn-App/src/main/res/layout/include_onboarding.xml @@ -63,7 +63,7 @@ <variable name="countryData" - type="java.util.List<String>" /> + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> </data> diff --git a/Corona-Warn-App/src/main/res/layout/include_submission_positive_other_warning.xml b/Corona-Warn-App/src/main/res/layout/include_submission_positive_other_warning.xml index 96601edf2aa0af2f62c85a246f769247d6c45dff..2786f6c2d7e67e6e611ae7e83c2d56e92d71edd7 100644 --- a/Corona-Warn-App/src/main/res/layout/include_submission_positive_other_warning.xml +++ b/Corona-Warn-App/src/main/res/layout/include_submission_positive_other_warning.xml @@ -8,7 +8,7 @@ <variable name="countryData" - type="java.util.List<String>" /> + type="java.util.List<de.rki.coronawarnapp.ui.Country>" /> </data> diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationServiceTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationServiceTest.kt deleted file mode 100644 index bfa68c95fc0416c210b03da08d6126c230b9bba7..0000000000000000000000000000000000000000 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationServiceTest.kt +++ /dev/null @@ -1,62 +0,0 @@ -package de.rki.coronawarnapp.service.applicationconfiguration - -import de.rki.coronawarnapp.appconfig.AppConfigProvider -import de.rki.coronawarnapp.server.protocols.ApplicationConfigurationOuterClass -import de.rki.coronawarnapp.util.CWADebug -import de.rki.coronawarnapp.util.di.AppInjector -import de.rki.coronawarnapp.util.di.ApplicationComponent -import io.kotest.matchers.shouldBe -import io.mockk.coEvery -import io.mockk.every -import io.mockk.mockk -import io.mockk.mockkObject -import io.mockk.verify -import kotlinx.coroutines.runBlocking -import org.junit.Test -import testhelpers.BaseTest - -class ApplicationConfigurationServiceTest : BaseTest() { - - @Test - fun `mock country codes only in debug`() { - mockkObject(CWADebug) - every { CWADebug.isDebugBuildOrMode } returns true - - CWADebug.isDebugBuildOrMode shouldBe true - - val appConfig = mockk<ApplicationConfigurationOuterClass.ApplicationConfiguration>() - val appConfigBuilder = - mockk<ApplicationConfigurationOuterClass.ApplicationConfiguration.Builder>() - - every { appConfig.toBuilder() } returns appConfigBuilder - - every { appConfigBuilder.addAllSupportedCountries(any()) } returns appConfigBuilder - - every { appConfigBuilder.clearSupportedCountries() } returns appConfigBuilder - - every { appConfigBuilder.build() } returns appConfig - - val downloadServer = mockk<AppConfigProvider>() - coEvery { downloadServer.getAppConfig() } returns appConfig - - mockkObject(AppInjector) - mockk<ApplicationComponent>().apply { - every { this@apply.appConfigProvider } returns downloadServer - every { AppInjector.component } returns this@apply - } - - runBlocking { - ApplicationConfigurationService.asyncRetrieveApplicationConfiguration() - verify(exactly = 1) { appConfigBuilder.addAllSupportedCountries(any()) } - } - - every { CWADebug.isDebugBuildOrMode } returns false - - CWADebug.isDebugBuildOrMode shouldBe false - - runBlocking { - ApplicationConfigurationService.asyncRetrieveApplicationConfiguration() - verify(exactly = 1) { appConfigBuilder.addAllSupportedCountries(any()) } - } - } -} diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentViewModelTest.kt index a5d1b05dd95ac53bc75d2694bdeb4e7f1629a721..d5e13842a13a8de0cdacbd91bffca9cae2b65fce 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/ui/interoperability/InteroperabilityConfigurationFragmentViewModelTest.kt @@ -2,70 +2,58 @@ package de.rki.coronawarnapp.ui.interoperability import androidx.lifecycle.MutableLiveData import de.rki.coronawarnapp.storage.interoperability.InteroperabilityRepository +import de.rki.coronawarnapp.ui.Country +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.junit5.MockKExtension +import io.mockk.just import io.mockk.verify -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith -import org.junit.jupiter.api.extension.Extensions import testhelpers.extensions.InstantExecutorExtension import testhelpers.extensions.getOrAwaitValue -@Extensions( - ExtendWith(MockKExtension::class), - ExtendWith(InstantExecutorExtension::class) -) +@ExtendWith(InstantExecutorExtension::class) class InteroperabilityConfigurationFragmentViewModelTest { - @MockK(relaxUnitFun = true) - lateinit var interoperabilityRepository: InteroperabilityRepository - - private lateinit var interoperabilityConfigurationFragmentViewModel: InteroperabilityConfigurationFragmentViewModel - - private val countryListLiveData = MutableLiveData<List<String>>(listOf()) + @MockK lateinit var interoperabilityRepository: InteroperabilityRepository @BeforeEach fun setupFreshViewModel() { - every { interoperabilityRepository.countryList } returns countryListLiveData - interoperabilityConfigurationFragmentViewModel = - InteroperabilityConfigurationFragmentViewModel(interoperabilityRepository) + MockKAnnotations.init(this) + + every { interoperabilityRepository.countryList } returns MutableLiveData( + Country.values().toList() + ) + every { interoperabilityRepository.getAllCountries() } just Runs } + private fun createViewModel() = + InteroperabilityConfigurationFragmentViewModel(interoperabilityRepository) + @Test - fun countryListIsEmptyIfRepositoryReturnsNoData() { - val countryList = - interoperabilityConfigurationFragmentViewModel.countryList.getOrAwaitValue() + fun `viewmodel returns interop repo countryList`() { + val vm = createViewModel() - assertTrue(countryList.isEmpty()) + vm.countryList.getOrAwaitValue() shouldBe Country.values().toList() } @Test fun testFetchCountryList() { - val countryListFetched = listOf( - "DE", "UK", "FR", "IT", "ES", "PL", "RO", "NL", - "BE", "CZ", "SE", "PT", "HU", "AT", "CH", "BG", "DK", "FI", "SK", - "NO", "IE", "HR", "SI", "LT", "LV", "EE", "CY", "LU", "MT", "IS" - ) - - interoperabilityRepository.getAllCountries() - countryListLiveData.value = countryListFetched - - val countryList = - interoperabilityConfigurationFragmentViewModel.countryList.getOrAwaitValue() - - assertEquals(countryList.size, countryListFetched.size) - assertTrue(countryList == countryListFetched) - verify { interoperabilityRepository.getAllCountries() } + val vm = createViewModel() + verify(exactly = 0) { interoperabilityRepository.getAllCountries() } + vm.getAllCountries() + verify(exactly = 1) { interoperabilityRepository.getAllCountries() } } @Test fun testBackPressButton() { - interoperabilityConfigurationFragmentViewModel.onBackPressed() + val vm = createViewModel() + vm.onBackPressed() - assertTrue(interoperabilityConfigurationFragmentViewModel.navigateBack.getOrAwaitValue()) + vm.navigateBack.getOrAwaitValue() shouldBe true } }