diff --git a/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtilTest.kt b/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtilTest.kt index ce123ecda..a5c7ad021 100644 --- a/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtilTest.kt +++ b/app/src/androidTest/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtilTest.kt @@ -8,11 +8,14 @@ package ee.ria.DigiDoc.utils.locale import android.content.Context import android.content.SharedPreferences import android.content.res.Resources +import android.os.LocaleList import androidx.preference.PreferenceManager import androidx.test.platform.app.InstrumentationRegistry +import ee.ria.DigiDoc.R import ee.ria.DigiDoc.common.Constant.KEY_LOCALE import ee.ria.DigiDoc.utilsLib.locale.LocaleUtil.getLocale import junit.framework.TestCase.assertEquals +import junit.framework.TestCase.assertTrue import org.junit.Before import org.junit.Test import org.mockito.ArgumentMatchers.any @@ -78,4 +81,69 @@ class LocaleUtilTest { assertEquals(result, mockContext) assertEquals(Locale.getDefault(), newLocale) } + + @Test + fun localeUtil_createLocalizedContext_usesSelectedLanguageOverDeviceLanguage() { + val context = InstrumentationRegistry.getInstrumentation().targetContext + + val result = + localeUtil.createLocalizedContext(context, getLocale("en"), LocaleList.forLanguageTags("et-EE")) + + assertEnglish(result) + } + + @Test + fun localeUtil_createLocalizedContext_usesSelectedEstonianOnEnglishDevice() { + val context = InstrumentationRegistry.getInstrumentation().targetContext + + val result = + localeUtil.createLocalizedContext(context, getLocale("et"), LocaleList.forLanguageTags("en-US")) + + assertEstonian(result) + } + + @Test + fun localeUtil_createLocalizedContext_usesDeviceLanguageWhenNoneSelected() { + val context = InstrumentationRegistry.getInstrumentation().targetContext + + val result = localeUtil.createLocalizedContext(context, null, LocaleList.forLanguageTags("et-EE")) + + assertEstonian(result) + } + + @Test + fun localeUtil_createLocalizedContext_usesFirstSupportedPreferredDeviceLanguage() { + val context = InstrumentationRegistry.getInstrumentation().targetContext + + val result = localeUtil.createLocalizedContext(context, null, LocaleList.forLanguageTags("fi-FI,et-EE")) + + assertEstonian(result) + } + + @Test + fun localeUtil_createLocalizedContext_fallsBackToEnglishForUnsupportedDeviceLanguage() { + val context = InstrumentationRegistry.getInstrumentation().targetContext + + val result = localeUtil.createLocalizedContext(context, null, LocaleList.forLanguageTags("fi-FI")) + + assertEnglish(result) + } + + private fun assertEstonian(context: Context) { + assertTrue( + context + .getString(R.string.unsupported_version_message, "www.id.ee") + .startsWith("Sinu nutiseadmes olev ID-tarkvara"), + ) + assertTrue(context.getString(R.string.rooted_device).startsWith("Seda rakendust ei saa kasutada")) + } + + private fun assertEnglish(context: Context) { + assertTrue( + context + .getString(R.string.unsupported_version_message, "www.id.ee") + .startsWith("This version of ID-software on your smart device"), + ) + assertTrue(context.getString(R.string.rooted_device).startsWith("This app cannot be used")) + } } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/MainActivity.kt b/app/src/main/kotlin/ee/ria/DigiDoc/MainActivity.kt index 0eeef0425..89f956937 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/MainActivity.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/MainActivity.kt @@ -8,12 +8,19 @@ package ee.ria.DigiDoc import android.content.Context import android.content.Intent import android.content.pm.PackageManager +import android.content.res.Resources import android.os.Build import android.os.Bundle import android.provider.Browser import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge +import androidx.activity.viewModels +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.remember +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalResources import androidx.core.app.ActivityCompat import androidx.core.net.toUri import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen @@ -28,6 +35,7 @@ import ee.ria.DigiDoc.common.model.AppState import ee.ria.DigiDoc.domain.model.theme.ThemeSetting import ee.ria.DigiDoc.domain.preferences.DataStore import ee.ria.DigiDoc.fragment.RootFragment +import ee.ria.DigiDoc.fragment.UnsupportedVersionFragment import ee.ria.DigiDoc.init.LibrarySetup import ee.ria.DigiDoc.manager.ActivityManager import ee.ria.DigiDoc.root.RootChecker @@ -43,6 +51,7 @@ import ee.ria.DigiDoc.utilsLib.file.FileUtil.getLogsDirectory import ee.ria.DigiDoc.utilsLib.locale.LocaleUtil.getLocale import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.debugLog +import ee.ria.DigiDoc.viewmodel.UnsupportedVersionViewModel import kotlinx.coroutines.CancellationException import kotlinx.coroutines.launch import java.util.logging.Logger @@ -76,6 +85,8 @@ class MainActivity : @Inject lateinit var secureUtil: SecureUtil + private val unsupportedVersionViewModel: UnsupportedVersionViewModel by viewModels() + private val logTag = "MainActivity" private var isAppReady = false @@ -106,7 +117,9 @@ class MainActivity : isAppReady = true setContent { RIADigiDocTheme(darkTheme = useDarkMode) { - RootFragment() + BlockingScreenLocale { + RootFragment() + } } } return @@ -176,13 +189,23 @@ class MainActivity : } } + val isAppVersionUnsupported = + unsupportedVersionViewModel.isAppVersionUnsupported( + "${BuildConfig.VERSION_NAME}.${BuildConfig.VERSION_CODE}", + ) setContent { RIADigiDocTheme(darkTheme = useDarkMode) { - RIADigiDocAppScreen( - externalFileUris = externalFileUris, - webEidUri = webEidUri, - browserPackage = browserPackage, - ) + if (isAppVersionUnsupported) { + BlockingScreenLocale { + UnsupportedVersionFragment() + } + } else { + RIADigiDocAppScreen( + externalFileUris = externalFileUris, + webEidUri = webEidUri, + browserPackage = browserPackage, + ) + } } } } @@ -206,6 +229,23 @@ class MainActivity : AppState.isAppInForeground = false } + @Composable + private fun BlockingScreenLocale(content: @Composable () -> Unit) { + val localizedContext = + remember { + localeUtil.createLocalizedContext( + this, + dataStore.getLocale(), + Resources.getSystem().configuration.locales, + ) + } + CompositionLocalProvider( + LocalContext provides localizedContext, + LocalResources provides localizedContext.resources, + content = content, + ) + } + private fun isSystemModeEnabled(dataStore: DataStore): Boolean = dataStore.getThemeSetting() == ThemeSetting.SYSTEM private fun isDarkModeEnabled(dataStore: DataStore): Boolean = dataStore.getThemeSetting() == ThemeSetting.DARK diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/UnsupportedVersionFragment.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/UnsupportedVersionFragment.kt new file mode 100644 index 000000000..aac08bca2 --- /dev/null +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/UnsupportedVersionFragment.kt @@ -0,0 +1,49 @@ +// SPDX-FileCopyrightText: Estonian Information System Authority +// SPDX-License-Identifier: LGPL-2.1-or-later + +@file:Suppress("PackageName", "FunctionName") + +package ee.ria.DigiDoc.fragment + +import android.content.res.Configuration +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Surface +import androidx.compose.runtime.Composable +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTagsAsResourceId +import androidx.compose.ui.tooling.preview.Preview +import ee.ria.DigiDoc.fragment.screen.UnsupportedVersionScreen +import ee.ria.DigiDoc.ui.theme.RIADigiDocTheme + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +fun UnsupportedVersionFragment(modifier: Modifier = Modifier) { + Surface( + modifier = + modifier + .fillMaxSize() + .background(MaterialTheme.colorScheme.background) + .semantics { + testTagsAsResourceId = true + }.testTag("unsupportedVersionFragment"), + color = MaterialTheme.colorScheme.background, + ) { + UnsupportedVersionScreen( + modifier = modifier, + ) + } +} + +@Preview(showBackground = true) +@Preview(showBackground = true, uiMode = Configuration.UI_MODE_NIGHT_YES) +@Composable +fun UnsupportedVersionFragmentPreview() { + RIADigiDocTheme { + UnsupportedVersionFragment() + } +} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/UnsupportedVersionScreen.kt b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/UnsupportedVersionScreen.kt new file mode 100644 index 000000000..7efcb9cb2 --- /dev/null +++ b/app/src/main/kotlin/ee/ria/DigiDoc/fragment/screen/UnsupportedVersionScreen.kt @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: Estonian Information System Authority +// SPDX-License-Identifier: LGPL-2.1-or-later + +@file:Suppress("PackageName", "FunctionName") + +package ee.ria.DigiDoc.fragment.screen + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Scaffold +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.ExperimentalComposeUiApi +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.semantics +import androidx.compose.ui.semantics.testTagsAsResourceId +import androidx.compose.ui.text.LinkAnnotation +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.TextLinkStyles +import androidx.compose.ui.text.buildAnnotatedString +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextDecoration +import ee.ria.DigiDoc.R +import ee.ria.DigiDoc.ui.component.shared.InvisibleElement +import ee.ria.DigiDoc.ui.theme.Dimensions.SPadding + +@OptIn(ExperimentalComposeUiApi::class) +@Composable +fun UnsupportedVersionScreen(modifier: Modifier = Modifier) { + val linkText = stringResource(R.string.unsupported_version_link_text) + val message = stringResource(R.string.unsupported_version_message, linkText) + val url = stringResource(R.string.unsupported_version_url) + val linkColor = MaterialTheme.colorScheme.primary + + val annotatedMessage = + buildAnnotatedString { + append(message) + val linkStart = message.indexOf(linkText) + if (linkStart >= 0) { + addLink( + LinkAnnotation.Url( + url = url, + styles = + TextLinkStyles( + style = + SpanStyle( + color = linkColor, + textDecoration = TextDecoration.Underline, + ), + ), + ), + linkStart, + linkStart + linkText.length, + ) + } + } + + Scaffold( + modifier = + modifier + .semantics { + testTagsAsResourceId = true + }.testTag("unsupportedVersionScreen"), + ) { innerPadding -> + Column( + modifier = modifier.padding(innerPadding), + ) { + Box( + modifier = + modifier + .padding(SPadding) + .fillMaxSize() + .verticalScroll(rememberScrollState()) + .testTag("scrollView"), + contentAlignment = Alignment.Center, + ) { + Text( + text = annotatedMessage, + style = MaterialTheme.typography.bodyLarge, + modifier = + modifier + .padding(vertical = SPadding) + .testTag("unsupportedVersionMessage"), + textAlign = TextAlign.Center, + color = MaterialTheme.colorScheme.onSurface, + ) + InvisibleElement(modifier = modifier) + } + } + } +} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/utils/VersionUtil.kt b/app/src/main/kotlin/ee/ria/DigiDoc/utils/VersionUtil.kt new file mode 100644 index 000000000..59a4ed3b7 --- /dev/null +++ b/app/src/main/kotlin/ee/ria/DigiDoc/utils/VersionUtil.kt @@ -0,0 +1,39 @@ +// SPDX-FileCopyrightText: Estonian Information System Authority +// SPDX-License-Identifier: LGPL-2.1-or-later + +@file:Suppress("PackageName") + +package ee.ria.DigiDoc.utils + +object VersionUtil { + fun isLowerThan( + version: String, + otherVersion: String?, + ): Boolean { + val segments = segments(version) + val otherSegments = segments(otherVersion.orEmpty()) + if (segments.isEmpty() || otherSegments.isEmpty()) { + return false + } + + val length = maxOf(segments.size, otherSegments.size) + for (index in 0 until length) { + val segment = segments.getOrElse(index) { 0 } + val otherSegment = otherSegments.getOrElse(index) { 0 } + if (segment != otherSegment) { + return segment < otherSegment + } + } + return false + } + + private fun segments(version: String): List = + version + .trim() + .split('.') + .asSequence() + .map { it.toIntOrNull() } + .takeWhile { it != null && it >= 0 } + .filterNotNull() + .toList() +} diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtil.kt b/app/src/main/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtil.kt index bc2e8d2d5..49194f557 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtil.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtil.kt @@ -6,6 +6,7 @@ package ee.ria.DigiDoc.utils.locale import android.content.Context +import android.os.LocaleList import java.util.Locale interface LocaleUtil { @@ -15,4 +16,10 @@ interface LocaleUtil { context: Context, locale: Locale, ): Context + + fun createLocalizedContext( + context: Context, + selectedLocale: Locale?, + deviceLocales: LocaleList, + ): Context } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtilImpl.kt b/app/src/main/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtilImpl.kt index 38585c37b..2c9bd631a 100644 --- a/app/src/main/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtilImpl.kt +++ b/app/src/main/kotlin/ee/ria/DigiDoc/utils/locale/LocaleUtilImpl.kt @@ -6,6 +6,8 @@ package ee.ria.DigiDoc.utils.locale import android.content.Context +import android.content.res.Configuration +import android.os.LocaleList import androidx.preference.PreferenceManager import ee.ria.DigiDoc.common.Constant.KEY_LOCALE import java.util.Locale @@ -31,4 +33,14 @@ class LocaleUtilImpl config.setLayoutDirection(locale) return context.createConfigurationContext(config) } + + override fun createLocalizedContext( + context: Context, + selectedLocale: Locale?, + deviceLocales: LocaleList, + ): Context { + val configuration = Configuration(context.resources.configuration) + configuration.setLocales(selectedLocale?.let { LocaleList(it) } ?: deviceLocales) + return context.createConfigurationContext(configuration) + } } diff --git a/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/UnsupportedVersionViewModel.kt b/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/UnsupportedVersionViewModel.kt new file mode 100644 index 000000000..7d78db6d6 --- /dev/null +++ b/app/src/main/kotlin/ee/ria/DigiDoc/viewmodel/UnsupportedVersionViewModel.kt @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Estonian Information System Authority +// SPDX-License-Identifier: LGPL-2.1-or-later + +@file:Suppress("PackageName") + +package ee.ria.DigiDoc.viewmodel + +import androidx.lifecycle.ViewModel +import dagger.hilt.android.lifecycle.HiltViewModel +import ee.ria.DigiDoc.configuration.loader.ConfigurationLoader +import ee.ria.DigiDoc.utils.VersionUtil +import ee.ria.DigiDoc.utilsLib.logging.LoggingUtil.Companion.errorLog +import javax.inject.Inject + +@HiltViewModel +class UnsupportedVersionViewModel + @Inject + constructor( + private val configurationLoader: ConfigurationLoader, + ) : ViewModel() { + private val logTag = "UnsupportedVersionViewModel" + + private var isUnsupported: Boolean? = null + + fun isAppVersionUnsupported(appVersion: String): Boolean { + isUnsupported?.let { return it } + + val unsupportedVersion = configurationLoader.getConfigurationFlow().value?.riaddUnsupported + val result = VersionUtil.isLowerThan(appVersion, unsupportedVersion) + if (result) { + errorLog(logTag, "App version $appVersion is unsupported") + } + isUnsupported = result + return result + } + } diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml index 25baf8d60..9a0bc2e74 100644 --- a/app/src/main/res/values-et/strings.xml +++ b/app/src/main/res/values-et/strings.xml @@ -21,6 +21,8 @@ Jätka Seda rakendust ei saa kasutada turvamata (ingl rooted) seadmes. + Sinu nutiseadmes olev ID-tarkvara ei ole toetatud. RIA DigiDoc kasutamiseks pead rakendust uuendama. Paigalda uus ID-tarkvara veebilehelt %1$s + https://www.id.ee/artikkel/paigalda-id-tarkvara/ Konfiguratsiooni initsialiseerimine ebaõnnestus Midagi läks valesti, proovi uuesti diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index 6ac55c1a2..6eda5abe9 100644 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -17,6 +17,7 @@ English Invisible element + www.id.ee libdigidocpp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a41d9f0b9..6a68d8879 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -21,6 +21,8 @@ Continue This app cannot be used in rooted device. + This version of ID-software on your smart device is unsupported. RIA DigiDoc cannot be used until you update ID-software. Install new ID-software from %1$s + https://www.id.ee/en/article/install-id-software/ Failed to initialize configuration Something went wrong, try again diff --git a/app/src/test/kotlin/ee/ria/DigiDoc/utils/VersionUtilTest.kt b/app/src/test/kotlin/ee/ria/DigiDoc/utils/VersionUtilTest.kt new file mode 100644 index 000000000..6473b3b8f --- /dev/null +++ b/app/src/test/kotlin/ee/ria/DigiDoc/utils/VersionUtilTest.kt @@ -0,0 +1,71 @@ +// SPDX-FileCopyrightText: Estonian Information System Authority +// SPDX-License-Identifier: LGPL-2.1-or-later + +@file:Suppress("PackageName") + +package ee.ria.DigiDoc.utils + +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test + +class VersionUtilTest { + @Test + fun versionUtil_isLowerThan_returnTrueWhenBuildNumberIsLower() { + assertTrue(VersionUtil.isLowerThan("3.2.0.100", "3.2.0.101")) + } + + @Test + fun versionUtil_isLowerThan_returnTrueWhenMinorIsLowerDespiteHigherBuildNumber() { + assertTrue(VersionUtil.isLowerThan("3.1.9.999", "3.2.0.1")) + } + + @Test + fun versionUtil_isLowerThan_comparesSegmentsNumericallyNotLexically() { + assertTrue(VersionUtil.isLowerThan("3.9.0.1", "3.10.0.1")) + assertFalse(VersionUtil.isLowerThan("3.10.0.1", "3.9.0.1")) + } + + @Test + fun versionUtil_isLowerThan_returnFalseWhenEqual() { + assertFalse(VersionUtil.isLowerThan("3.2.0.100", "3.2.0.100")) + } + + @Test + fun versionUtil_isLowerThan_returnFalseWhenHigher() { + assertFalse(VersionUtil.isLowerThan("3.2.1.1", "3.2.0.500")) + } + + @Test + fun versionUtil_isLowerThan_treatsMissingSegmentsAsZero() { + assertTrue(VersionUtil.isLowerThan("3.2", "3.2.0.1")) + assertFalse(VersionUtil.isLowerThan("3.2.0.0", "3.2")) + assertFalse(VersionUtil.isLowerThan("3.2.0.1", "3.2")) + } + + @Test + fun versionUtil_isLowerThan_returnFalseWhenOtherVersionIsNull() { + assertFalse(VersionUtil.isLowerThan("3.2.0.100", null)) + } + + @Test + fun versionUtil_isLowerThan_returnFalseWhenOtherVersionIsBlank() { + assertFalse(VersionUtil.isLowerThan("3.2.0.100", " ")) + } + + @Test + fun versionUtil_isLowerThan_returnFalseWhenOtherVersionIsNotNumeric() { + assertFalse(VersionUtil.isLowerThan("3.2.0.100", "latest")) + } + + @Test + fun versionUtil_isLowerThan_ignoresTrailingNonNumericSuffix() { + assertTrue(VersionUtil.isLowerThan("3.2.0.100", "3.3.0-beta")) + assertFalse(VersionUtil.isLowerThan("3.3.0.1", "3.3.0-beta")) + } + + @Test + fun versionUtil_isLowerThan_trimsWhitespace() { + assertTrue(VersionUtil.isLowerThan("3.2.0.100", " 3.2.0.101 ")) + } +} diff --git a/app/src/test/kotlin/ee/ria/DigiDoc/viewmodel/UnsupportedVersionViewModelTest.kt b/app/src/test/kotlin/ee/ria/DigiDoc/viewmodel/UnsupportedVersionViewModelTest.kt new file mode 100644 index 000000000..f64320866 --- /dev/null +++ b/app/src/test/kotlin/ee/ria/DigiDoc/viewmodel/UnsupportedVersionViewModelTest.kt @@ -0,0 +1,87 @@ +// SPDX-FileCopyrightText: Estonian Information System Authority +// SPDX-License-Identifier: LGPL-2.1-or-later + +@file:Suppress("PackageName") + +package ee.ria.DigiDoc.viewmodel + +import ee.ria.DigiDoc.configuration.loader.ConfigurationLoader +import ee.ria.DigiDoc.configuration.provider.ConfigurationProvider +import kotlinx.coroutines.flow.MutableStateFlow +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.mock +import org.mockito.Mockito.`when` +import org.mockito.junit.MockitoJUnitRunner + +@RunWith(MockitoJUnitRunner::class) +class UnsupportedVersionViewModelTest { + @Mock + private lateinit var configurationLoader: ConfigurationLoader + + private val configurationFlow = MutableStateFlow(null) + + private lateinit var viewModel: UnsupportedVersionViewModel + + @Before + fun setUp() { + `when`(configurationLoader.getConfigurationFlow()).thenReturn(configurationFlow) + viewModel = UnsupportedVersionViewModel(configurationLoader) + } + + @Test + fun unsupportedVersionViewModel_isAppVersionUnsupported_returnTrueWhenAppVersionIsLower() { + configurationFlow.value = configuration("3.2.0.200") + + assertTrue(viewModel.isAppVersionUnsupported("3.2.0.100")) + } + + @Test + fun unsupportedVersionViewModel_isAppVersionUnsupported_returnFalseWhenAppVersionIsNotLower() { + configurationFlow.value = configuration("3.2.0.100") + + assertFalse(viewModel.isAppVersionUnsupported("3.2.0.100")) + } + + @Test + fun unsupportedVersionViewModel_isAppVersionUnsupported_returnFalseWhenKeyIsMissing() { + configurationFlow.value = configuration(null) + + assertFalse(viewModel.isAppVersionUnsupported("3.2.0.100")) + } + + @Test + fun unsupportedVersionViewModel_isAppVersionUnsupported_returnFalseWhenConfigurationIsNotLoaded() { + assertFalse(viewModel.isAppVersionUnsupported("3.2.0.100")) + } + + @Test + fun unsupportedVersionViewModel_isAppVersionUnsupported_ignoresConfigurationUpdatedAfterFirstCheck() { + configurationFlow.value = configuration(null) + assertFalse(viewModel.isAppVersionUnsupported("3.2.0.100")) + + configurationFlow.value = configuration("3.2.0.200") + + assertFalse(viewModel.isAppVersionUnsupported("3.2.0.100")) + } + + @Test + fun unsupportedVersionViewModel_isAppVersionUnsupported_staysUnsupportedAfterConfigurationUpdate() { + configurationFlow.value = configuration("3.2.0.200") + assertTrue(viewModel.isAppVersionUnsupported("3.2.0.100")) + + configurationFlow.value = configuration(null) + + assertTrue(viewModel.isAppVersionUnsupported("3.2.0.100")) + } + + private fun configuration(riaddUnsupported: String?): ConfigurationProvider { + val configuration = mock(ConfigurationProvider::class.java) + `when`(configuration.riaddUnsupported).thenReturn(riaddUnsupported) + return configuration + } +} diff --git a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/provider/ConfigurationProvider.kt b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/provider/ConfigurationProvider.kt index 1d7e290e1..fb8622eea 100644 --- a/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/provider/ConfigurationProvider.kt +++ b/config-lib/src/main/kotlin/ee/ria/DigiDoc/configuration/provider/ConfigurationProvider.kt @@ -34,6 +34,7 @@ data class ConfigurationProvider( @SerializedName("LDAP-CERTS") val ldapCerts: List = listOf(), var configurationLastUpdateCheckDate: Date?, var configurationUpdateDate: Date?, + @SerializedName("RIADD-UNSUPPORTED") val riaddUnsupported: String? = null, ) { data class MetaInf( @SerializedName("URL") val url: String, diff --git a/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/provider/ConfigurationProviderTest.kt b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/provider/ConfigurationProviderTest.kt new file mode 100644 index 000000000..f2929c1ee --- /dev/null +++ b/config-lib/src/test/kotlin/ee/ria/DigiDoc/configuration/provider/ConfigurationProviderTest.kt @@ -0,0 +1,35 @@ +// SPDX-FileCopyrightText: Estonian Information System Authority +// SPDX-License-Identifier: LGPL-2.1-or-later + +@file:Suppress("PackageName") + +package ee.ria.DigiDoc.configuration.provider + +import com.google.gson.Gson +import org.junit.Assert.assertEquals +import org.junit.Assert.assertNull +import org.junit.Test + +class ConfigurationProviderTest { + @Test + fun configurationProvider_deserialize_readsRiaddUnsupported() { + val configuration = + Gson().fromJson( + """{"RIADD-UNSUPPORTED":"3.2.0.100","QDIGIDOC4-UNSUPPORTED":"4.8.0.0"}""", + ConfigurationProvider::class.java, + ) + + assertEquals("3.2.0.100", configuration.riaddUnsupported) + } + + @Test + fun configurationProvider_deserialize_riaddUnsupportedIsNullWhenMissing() { + val configuration = + Gson().fromJson( + """{"QDIGIDOC4-UNSUPPORTED":"4.8.0.0"}""", + ConfigurationProvider::class.java, + ) + + assertNull(configuration.riaddUnsupported) + } +}