From 1a08c25e9281d308972c0b2afa69b893c740f71f Mon Sep 17 00:00:00 2001
From: Matthias Urhahn <matthias.urhahn@sap.com>
Date: Mon, 5 Oct 2020 08:56:47 +0200
Subject: [PATCH] Better handling of unexpected supportedCountryData from the
 server (DEV) (#1301)

* Better handling of unexpected supportedCountryData from the server.
Perform sanity checks on country data.
Map values to known `Country` enum.

* Fix unit test regression.

* Fix unit test regression.
---
 .../appconfig/AppConfigProvider.kt            | 27 +++++++-
 .../ApplicationConfigurationService.kt        | 19 +-----
 .../InteroperabilityRepository.kt             | 23 ++++---
 .../java/de/rki/coronawarnapp/ui/Country.kt   | 44 +++++++++++++
 .../rki/coronawarnapp/ui/view/CountryList.kt  | 62 ++++--------------
 .../ui/viewmodel/SubmissionViewModel.kt       |  9 ++-
 .../util/di/ApplicationComponent.kt           |  3 +
 ...ragment_interoperability_configuration.xml |  2 +-
 ...ment_onboarding_delta_interoperability.xml |  2 +-
 .../layout/fragment_onboarding_tracing.xml    |  2 +-
 ..._list_participating_countries_overview.xml |  2 +-
 .../res/layout/include_interoperability.xml   |  2 +-
 .../main/res/layout/include_onboarding.xml    |  2 +-
 ...lude_submission_positive_other_warning.xml |  2 +-
 .../ApplicationConfigurationServiceTest.kt    | 62 ------------------
 ...ilityConfigurationFragmentViewModelTest.kt | 64 ++++++++-----------
 16 files changed, 141 insertions(+), 186 deletions(-)
 create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/ui/Country.kt
 delete mode 100644 Corona-Warn-App/src/test/java/de/rki/coronawarnapp/service/applicationconfiguration/ApplicationConfigurationServiceTest.kt

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 47810d450..8ee5e8945 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 4c9e23a42..e82f912b2 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 4a3e76903..90768259c 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 000000000..2c22c8b00
--- /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 48325e263..a97986690 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 800dcc821..5f2c6cbda 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 7f90b2cf5..ff0449833 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 a0d7a6b25..5061f0307 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&lt;String&gt;" />
+            type="java.util.List&lt;de.rki.coronawarnapp.ui.Country&gt;" />
     </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 7b1ec16ca..c496d2382 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&lt;String&gt;" />
+            type="java.util.List&lt;de.rki.coronawarnapp.ui.Country&gt;" />
     </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 5fa04241d..07f2ea6b9 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&lt;String&gt;" />
+            type="java.util.List&lt;de.rki.coronawarnapp.ui.Country&gt;" />
     </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 4f5896f4d..f6142d91d 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&lt;String&gt;" />
+            type="java.util.List&lt;de.rki.coronawarnapp.ui.Country&gt;" />
 
         <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 b69a0dd4a..b1b874c9a 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&lt;String&gt;" />
+            type="java.util.List&lt;de.rki.coronawarnapp.ui.Country&gt;" />
 
         <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 f5c0341a4..148009f3a 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&lt;String&gt;" />
+            type="java.util.List&lt;de.rki.coronawarnapp.ui.Country&gt;" />
 
     </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 96601edf2..2786f6c2d 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&lt;String&gt;" />
+            type="java.util.List&lt;de.rki.coronawarnapp.ui.Country&gt;" />
 
     </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 bfa68c95f..000000000
--- 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 a5d1b05dd..d5e13842a 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
     }
 }
-- 
GitLab