From fc1489f6c7b6ceade0e65087c77ebc938efbab40 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 3 Nov 2025 14:29:19 +0200 Subject: [PATCH 1/2] [MS-1231] Adding a check for credential to see if it is already linked to the subject that needs to be enroled --- .../screen/EnrolLastBiometricViewModel.kt | 8 ++-- .../screen/EnrolLastBiometricViewModelTest.kt | 37 ++++++++++++++++++- 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/feature/enrol-last-biometric/src/main/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModel.kt b/feature/enrol-last-biometric/src/main/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModel.kt index 0522c2149d..fdb974f15d 100644 --- a/feature/enrol-last-biometric/src/main/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModel.kt +++ b/feature/enrol-last-biometric/src/main/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModel.kt @@ -56,7 +56,8 @@ internal class EnrolLastBiometricViewModel @Inject constructor( fun onViewCreated(params: EnrolLastBiometricParams) { viewModelScope.launch { params.scannedCredential?.let { scannedCredential -> - if (isCredentialLinkedToAnotherSubject(scannedCredential, params.projectId)) { + val guidToEnrol = getPreviousEnrolmentResult(params.steps)?.subjectId + if (isCredentialLinkedToAnotherSubject(scannedCredential, guidToEnrol = guidToEnrol, projectId = params.projectId)) { displayAddCredentialDialog(scannedCredential, params.projectId) return@launch } @@ -119,9 +120,10 @@ internal class EnrolLastBiometricViewModel @Inject constructor( private suspend fun isCredentialLinkedToAnotherSubject( scannedCredential: ScannedCredential?, + guidToEnrol: String?, projectId: String, ): Boolean { - if (scannedCredential == null) return false + if (scannedCredential == null || guidToEnrol == null) return false return enrolmentRecordRepository .load( @@ -129,7 +131,7 @@ internal class EnrolLastBiometricViewModel @Inject constructor( projectId = projectId, externalCredential = scannedCredential.credential, ), - ).isNotEmpty() + ).any { it.subjectId != guidToEnrol } } private fun getPreviousEnrolmentResult(steps: List) = diff --git a/feature/enrol-last-biometric/src/test/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModelTest.kt b/feature/enrol-last-biometric/src/test/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModelTest.kt index 80f74754c8..9fe5b1394d 100644 --- a/feature/enrol-last-biometric/src/test/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModelTest.kt +++ b/feature/enrol-last-biometric/src/test/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModelTest.kt @@ -73,6 +73,7 @@ internal class EnrolLastBiometricViewModelTest { lateinit var tokenizationProcessor: TokenizationProcessor private lateinit var viewModel: EnrolLastBiometricViewModel + private val guidToEnrol = "guidToEnrol" @Before fun setUp() { @@ -88,6 +89,8 @@ internal class EnrolLastBiometricViewModelTest { mockk { every { id } returns SESSION_ID }, ) + every { subject.subjectId } returns guidToEnrol + viewModel = EnrolLastBiometricViewModel( timeHelper = timeHelper, configManager = configManager, @@ -276,7 +279,13 @@ internal class EnrolLastBiometricViewModelTest { ) } returns decryptedCredential - viewModel.onViewCreated(createParams(listOf())) + viewModel.onViewCreated( + createParams( + listOf( + EnrolLastBiometricStepResult.EnrolLastBiometricsResult(subjectId = "anotherSubjectId"), + ), + ), + ) val result = viewModel.showAddCredentialDialog .test() @@ -290,6 +299,32 @@ internal class EnrolLastBiometricViewModelTest { coVerify(exactly = 0) { enrolmentRecordRepository.performActions(any(), any()) } } + @Test + fun `add credential dialog is not shown when credential is already linked to same subject`() = runTest { + val decryptedCredential = "decryptedCredential".asTokenizableRaw() + coEvery { enrolmentRecordRepository.load(any()) } returns listOf(subject) + coEvery { configManager.getProject(PROJECT_ID) } returns project + coEvery { + tokenizationProcessor.decrypt( + encrypted = scannedCredential.credential, + tokenKeyType = TokenKeyType.ExternalCredential, + project = project, + ) + } returns decryptedCredential + + viewModel.onViewCreated( + createParams( + listOf( + EnrolLastBiometricStepResult.EnrolLastBiometricsResult(subjectId = subject.subjectId), + ), + ), + ) + + viewModel.showAddCredentialDialog + .test() + .assertNoValue() + } + private fun createParams(steps: List) = EnrolLastBiometricParams( projectId = PROJECT_ID, userId = USER_ID, From 4dd440cc8177a6072a8ad1c4ef55413d34752d2e Mon Sep 17 00:00:00 2001 From: Sergejs Luhmirins Date: Tue, 4 Nov 2025 15:21:28 +0200 Subject: [PATCH 2/2] Improve code coverage --- .../screen/EnrolLastBiometricViewModelTest.kt | 53 ++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/feature/enrol-last-biometric/src/test/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModelTest.kt b/feature/enrol-last-biometric/src/test/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModelTest.kt index 9fe5b1394d..7d65a4c229 100644 --- a/feature/enrol-last-biometric/src/test/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModelTest.kt +++ b/feature/enrol-last-biometric/src/test/java/com/simprints/feature/enrollast/screen/EnrolLastBiometricViewModelTest.kt @@ -18,7 +18,6 @@ import com.simprints.infra.config.store.tokenization.TokenizationProcessor import com.simprints.infra.config.sync.ConfigManager import com.simprints.infra.enrolment.records.repository.EnrolmentRecordRepository import com.simprints.infra.enrolment.records.repository.domain.models.Subject -import com.simprints.infra.enrolment.records.repository.domain.models.SubjectQuery import com.simprints.infra.events.event.domain.models.BiometricReferenceCreationEvent import com.simprints.infra.events.event.domain.models.BiometricReferenceCreationEvent.BiometricReferenceCreationPayload import com.simprints.infra.events.event.domain.models.EnrolmentEventV4 @@ -299,6 +298,47 @@ internal class EnrolLastBiometricViewModelTest { coVerify(exactly = 0) { enrolmentRecordRepository.performActions(any(), any()) } } + @Test + fun `add credential dialog is not shown when there is no result`() = runTest { + val decryptedCredential = "decryptedCredential".asTokenizableRaw() + coEvery { enrolmentRecordRepository.load(any()) } returns listOf(subject) + coEvery { configManager.getProject(PROJECT_ID) } returns project + coEvery { + tokenizationProcessor.decrypt( + encrypted = scannedCredential.credential, + tokenKeyType = TokenKeyType.ExternalCredential, + project = project, + ) + } returns decryptedCredential + + viewModel.onViewCreated(createParams(steps = listOf())) + + viewModel.showAddCredentialDialog.test().assertNoValue() + } + + @Test + fun `add credential dialog is not shown when there are no credentials`() = runTest { + val decryptedCredential = "decryptedCredential".asTokenizableRaw() + coEvery { enrolmentRecordRepository.load(any()) } returns listOf(subject) + coEvery { configManager.getProject(PROJECT_ID) } returns project + coEvery { + tokenizationProcessor.decrypt( + encrypted = scannedCredential.credential, + tokenKeyType = TokenKeyType.ExternalCredential, + project = project, + ) + } returns decryptedCredential + + viewModel.onViewCreated( + createParams( + steps = listOf(EnrolLastBiometricStepResult.EnrolLastBiometricsResult(subjectId = subject.subjectId)), + credentials = null, + ), + ) + + viewModel.showAddCredentialDialog.test().assertNoValue() + } + @Test fun `add credential dialog is not shown when credential is already linked to same subject`() = runTest { val decryptedCredential = "decryptedCredential".asTokenizableRaw() @@ -320,17 +360,18 @@ internal class EnrolLastBiometricViewModelTest { ), ) - viewModel.showAddCredentialDialog - .test() - .assertNoValue() + viewModel.showAddCredentialDialog.test().assertNoValue() } - private fun createParams(steps: List) = EnrolLastBiometricParams( + private fun createParams( + steps: List, + credentials: ScannedCredential? = scannedCredential, + ) = EnrolLastBiometricParams( projectId = PROJECT_ID, userId = USER_ID, moduleId = MODULE_ID, steps = steps, - scannedCredential = scannedCredential, + scannedCredential = credentials, ) companion object {