From f0965a8d8bd600a88592e08bb7ec06017ae887c0 Mon Sep 17 00:00:00 2001 From: Matthias Urhahn <matthias.urhahn@sap.com> Date: Mon, 21 Jun 2021 18:05:26 +0200 Subject: [PATCH] Implement algorithm to find highest priority certificate (EXPOSUREAPP-7948) (#3510) * Implement algorithm to find highest priority certificate. * Fix conflicts and adjust tests. Co-authored-by: Mohamed Metwalli <mohamed.metwalli@sap.com> --- .../ui/TestCertificateDetailsFragmentTest.kt | 7 +- .../common/certificate/CwaCovidCertificate.kt | 2 + .../person/core/PersonCertificates.kt | 2 +- .../core/PersonCertificatesExtensions.kt | 229 ++++++++++++++++++ .../person/core/PersonCertificatesProvider.kt | 7 +- .../recovery/core/RecoveryCertificate.kt | 3 + .../storage/RecoveryCertificateContainer.kt | 3 + .../test/core/TestCertificate.kt | 3 + .../core/storage/TestCertificateContainer.kt | 4 + .../core/VaccinationCertificate.kt | 3 + .../storage/VaccinationContainer.kt | 3 + .../core/PersonCertificatesProviderTest.kt | 4 + .../ui/overview/PersonCertificatesData.kt | 5 + .../overview/PersonOverviewViewModelTest.kt | 34 ++- 14 files changed, 297 insertions(+), 12 deletions(-) create mode 100644 Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesExtensions.kt diff --git a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/test/ui/TestCertificateDetailsFragmentTest.kt b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/test/ui/TestCertificateDetailsFragmentTest.kt index 8f545721a..f283390d3 100644 --- a/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/test/ui/TestCertificateDetailsFragmentTest.kt +++ b/Corona-Warn-App/src/androidTest/java/de/rki/coronawarnapp/covidcertificate/test/ui/TestCertificateDetailsFragmentTest.kt @@ -14,15 +14,17 @@ import dagger.Module import dagger.android.ContributesAndroidInjector import de.rki.coronawarnapp.R import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier +import de.rki.coronawarnapp.covidcertificate.common.certificate.TestDccV1 import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString import de.rki.coronawarnapp.covidcertificate.common.repository.TestCertificateContainerId import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificate -import de.rki.coronawarnapp.covidcertificate.test.ui.details.TestCertificateDetailsViewModel import de.rki.coronawarnapp.covidcertificate.test.ui.details.TestCertificateDetailsFragment import de.rki.coronawarnapp.covidcertificate.test.ui.details.TestCertificateDetailsFragmentArgs +import de.rki.coronawarnapp.covidcertificate.test.ui.details.TestCertificateDetailsViewModel import io.mockk.MockKAnnotations import io.mockk.every import io.mockk.impl.annotations.MockK +import io.mockk.mockk import org.joda.time.DateTime import org.joda.time.Instant import org.joda.time.LocalDate @@ -88,6 +90,9 @@ class TestCertificateDetailsFragmentTest : BaseUITest() { val testDate = DateTime.parse("12.05.2021 19:00", formatter).toInstant() return MutableLiveData( object : TestCertificate { + override val rawCertificate: TestDccV1 + get() = mockk() + override val containerId: TestCertificateContainerId get() = TestCertificateContainerId("identifier") override val targetName: String diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CwaCovidCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CwaCovidCertificate.kt index 8f0481ca1..bf337960d 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CwaCovidCertificate.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/common/certificate/CwaCovidCertificate.kt @@ -27,4 +27,6 @@ interface CwaCovidCertificate { * The ID of the container holding this certificate in the CWA. */ val containerId: CertificateContainerId + + val rawCertificate: DccV1.MetaData } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificates.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificates.kt index 0c085098a..2567379ee 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificates.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificates.kt @@ -11,5 +11,5 @@ data class PersonCertificates( get() = certificates.first().personIdentifier val highestPriorityCertificate: CwaCovidCertificate - get() = certificates.first() + get() = certificates.findHighestPriorityCertificate() } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesExtensions.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesExtensions.kt new file mode 100644 index 000000000..18fcc6afd --- /dev/null +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesExtensions.kt @@ -0,0 +1,229 @@ +package de.rki.coronawarnapp.covidcertificate.person.core + +import de.rki.coronawarnapp.covidcertificate.common.certificate.CwaCovidCertificate +import de.rki.coronawarnapp.covidcertificate.recovery.core.RecoveryCertificate +import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificate +import de.rki.coronawarnapp.covidcertificate.vaccination.core.VaccinationCertificate +import de.rki.coronawarnapp.util.TimeAndDateExtensions.toLocalDateUtc +import org.joda.time.Days +import org.joda.time.Duration +import org.joda.time.Instant +import timber.log.Timber + +fun Collection<CwaCovidCertificate>.toCertificateSortOrder(): List<CwaCovidCertificate> { + return this.sortedBy { it.issuedAt } +} + +/** + * 1 + * PCR Test Certificate <= 48 hours + * Find Test Certificates (i.e. DGC with t[0]) where t[0].tt is set to LP6464-4 and the time difference between the + * time represented by t[0].sc and the current device time is <= 48 hours, sorted descending by t[0].sc + * (i.e. latest first). + * If there is one or more certificates matching these requirements, + * the first one is returned as a result of the operation. + */ +private fun Collection<CwaCovidCertificate>.rule1FindRecentPcrCertificate( + nowUtc: Instant +): CwaCovidCertificate? = this + .filterIsInstance<TestCertificate>() + .filter { it.rawCertificate.test.testType == "LP6464-4" } + .filter { Duration(it.rawCertificate.test.sampleCollectedAt, nowUtc) <= Duration.standardHours(48) } + .maxByOrNull { it.rawCertificate.test.sampleCollectedAt } + +/** + * 2 + * RAT Test Certificate <= 24 hours + * Find Test Certificates (i.e. DGC with t[0]) where t[0].tt is set to LP217198-3 and the time difference between + * the time represented by t[0].sc and the current device time is <= 24 hours, sorted descending by t[0].sc + * (i.e. latest first). + * If there is one or more certificates matching these requirements, + * the first one is returned as a result of the operation. + */ +private fun Collection<CwaCovidCertificate>.rule2FindRecentRaCertificate( + nowUtc: Instant +): CwaCovidCertificate? = this + .filterIsInstance<TestCertificate>() + .filter { it.rawCertificate.test.testType == "LP217198-3" } + .filter { Duration(it.rawCertificate.test.sampleCollectedAt, nowUtc) <= Duration.standardHours(24) } + .maxByOrNull { it.rawCertificate.test.sampleCollectedAt } + +/** + * 3 + * Series-completing Vaccination Certificate > 14 days: + * Find Vaccination Certificates (i.e. DGC with v[0]) where v[0].dn equal to v[0].sd and the time difference + * between the time represented by v[0].dt and the current device time is > 14 days, sorted descending by v[0].dt + * (i.e. latest first). + * If there is one or more certificates matching these requirements, + * the first one is returned as a result of the operation. + */ +private fun Collection<CwaCovidCertificate>.rule3FindRecentLastShot( + nowUtc: Instant +): CwaCovidCertificate? = this + .filterIsInstance<VaccinationCertificate>() + .filter { + with(it.rawCertificate.vaccination) { doseNumber == totalSeriesOfDoses } + } + .filter { + Days.daysBetween(it.rawCertificate.vaccination.vaccinatedAt, nowUtc.toLocalDateUtc()).days > 14 + } + .maxByOrNull { it.rawCertificate.vaccination.vaccinatedAt } + +/** + * 4 + * Recovery Certificate <= 180 days + * Find Recovery Certificates (i.e. DGC with r[0]) where the time difference between the time + * represented by r[0].df and the current device time is <= 180 days, sorted descending by r[0].df + * i.e. latest first). + * If there is one or more certificates matching these requirements, + * the first one is returned as a result of the operation. + */ +private fun Collection<CwaCovidCertificate>.rule4findRecentRecovery( + nowUtc: Instant +): CwaCovidCertificate? = this + .filterIsInstance<RecoveryCertificate>() + .filter { + Days.daysBetween(it.rawCertificate.recovery.validFrom, nowUtc.toLocalDateUtc()).days <= 180 + }.maxByOrNull { it.rawCertificate.recovery.validFrom } + +/** + * 5 + * Series-completing Vaccination Certificate <= 14 days + * Find Vaccination Certificates (i.e. DGC with v[0]) where v[0].dn equal to v[0].sd and the time difference + * between the time represented by v[0].dt and the current device time is <= 14 days, + * sorted descending by v[0].dt (i.e. latest first). + * If there is one or more certificates matching these requirements, + * the first one is returned as a result of the operation. + */ +private fun Collection<CwaCovidCertificate>.rule5findTooRecentFinalShot( + nowUtc: Instant +): CwaCovidCertificate? = this + .filterIsInstance<VaccinationCertificate>() + .filter { + with(it.rawCertificate.vaccination) { doseNumber == totalSeriesOfDoses } + } + .filter { + Days.daysBetween(it.rawCertificate.vaccination.vaccinatedAt, nowUtc.toLocalDateUtc()).days <= 14 + } + .maxByOrNull { it.rawCertificate.vaccination.vaccinatedAt } + +/** + * 6 + * Other Vaccination Certificate + * Find Vaccination Certificates (i.e. DGC with v[0])sorted descending by v[0].dt (i.e. latest first). + * If there is one or more certificates matching these requirements, + * the first one is returned as a result of the operation. + */ +private fun Collection<CwaCovidCertificate>.rule6findOtherVaccinations(): CwaCovidCertificate? = this + .filterIsInstance<VaccinationCertificate>() + .maxByOrNull { it.rawCertificate.vaccination.vaccinatedAt } + +/** + * 7 + * Recovery Certificate > 180 days + * Find Recovery Certificates (i.e. DGC with r[0]) where the time difference between the time represented by r[0].df + * and the current device time is > 180 days, sorted descending by r[0].df (i.e. latest first). + * If there is one or more certificates matching these requirements, + * the first one is returned as a result of the operation. + */ +private fun Collection<CwaCovidCertificate>.rule7FindOldRecovery( + nowUtc: Instant +): CwaCovidCertificate? = this + .filterIsInstance<RecoveryCertificate>() + .filter { + Days.daysBetween(it.rawCertificate.recovery.validFrom, nowUtc.toLocalDateUtc()).days > 180 + } + .maxByOrNull { it.rawCertificate.recovery.validFrom } + +/** + * 8 + * PCR Test Certificate > 48 hours + * Find Test Certificates (i.e. DGC with t[0]) where t[0].tt is set to LP6464-4 and the time difference between + * the time represented by t[0].sc and the current device time is > 48 hours, + * sorted descending by t[0].sc (i.e. latest first). + * If there is one or more certificates matching these requirements, + * the first one is returned as a result of the operation. + */ +private fun Collection<CwaCovidCertificate>.rule8FindOldPcrTest( + nowUtc: Instant +): CwaCovidCertificate? = this + .filterIsInstance<TestCertificate>() + .filter { it.rawCertificate.test.testType == "LP6464-4" } + .filter { Duration(it.rawCertificate.test.sampleCollectedAt, nowUtc) > Duration.standardHours(48) } + .maxByOrNull { it.rawCertificate.test.sampleCollectedAt } + +/** + * 9 + * RAT Test Certificate > 24 hours + * Find Test Certificates (i.e. DGC with t[0]) where t[0].tt is set to LP217198-3 and the time difference between + * the time represented by t[0].sc and the current device time is > 24 hours, + * sorted descending by t[0].sc (i.e. latest first). + * If there is one or more certificates matching these requirements, + * the first one is returned as a result of the operation. + */ +private fun Collection<CwaCovidCertificate>.rule9FindOldRaTest( + nowUtc: Instant +): CwaCovidCertificate? = this + .filterIsInstance<TestCertificate>() + .filter { it.rawCertificate.test.testType == "LP217198-3" } + .filter { Duration(it.rawCertificate.test.sampleCollectedAt, nowUtc) > Duration.standardHours(24) } + .maxByOrNull { it.rawCertificate.test.sampleCollectedAt } + +@Suppress("ReturnCount") +fun Collection<CwaCovidCertificate>.findHighestPriorityCertificate( + nowUtc: Instant = Instant.now() +): CwaCovidCertificate { + Timber.d("findHighestPriorityCertificate(nowUtc=%s): %s", nowUtc, this) + + rule1FindRecentPcrCertificate(nowUtc)?.let { + Timber.d("Rule 1 match (PCR Test Certificate <= 48 hours): %s", it) + return it + } + + rule2FindRecentRaCertificate(nowUtc)?.let { + Timber.d("Rule 2 match (RA Test Certificate <= 24 hours): %s", it) + return it + } + + rule3FindRecentLastShot(nowUtc)?.let { + Timber.d("Rule 3 match (Series-completing Vaccination Certificate > 14 days): %s", it) + return it + } + + rule4findRecentRecovery(nowUtc)?.let { + Timber.d("Rule 4 match (Recovery Certificate <= 180 days): %s", it) + return it + } + + rule5findTooRecentFinalShot(nowUtc)?.let { + Timber.d("Rule 5 match (Series-completing Vaccination Certificate <= 14 days): %s", it) + return it + } + + rule6findOtherVaccinations()?.let { + Timber.d("Rule 6 match (Other Vaccination Certificate): %s", it) + return it + } + + rule7FindOldRecovery(nowUtc)?.let { + Timber.d("Rule 7 match (Recovery Certificate > 180 days): %s", it) + return it + } + + rule8FindOldPcrTest(nowUtc)?.let { + Timber.d("Rule 8 match (PCR Test Certificate > 48 hours): %s", it) + return it + } + + rule9FindOldRaTest(nowUtc)?.let { + Timber.d("Rule 9 match (RAT Test Certificate > 24 hours): %s", it) + return it + } + + /** + * Fallback: return the first DGC from the set. + * Note that this fallback should never apply in a real scenario. + */ + Timber.e("No priority match, this should not happen: %s", this) + return first() +} diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesProvider.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesProvider.kt index 9621c268c..6487c5303 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesProvider.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesProvider.kt @@ -45,17 +45,12 @@ class PersonCertificatesProvider @Inject constructor( mapping.entries.map { (personIdentifier, certs) -> Timber.tag(TAG).v("PersonCertificates for %s with %d certs.", personIdentifier, certs.size) PersonCertificates( - certificates = certs.toPrioritySortOrder(), + certificates = certs.toCertificateSortOrder(), isCwaUser = personIdentifier == cwaUser, ) }.toSet() } - fun Collection<CwaCovidCertificate>.toPrioritySortOrder(): List<CwaCovidCertificate> { - // TODO - return this.toList() - } - /** * Set the current cwa user with regards to listed persons in the certificates tab. * After calling this [personCertificates] will emit new values. diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/recovery/core/RecoveryCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/recovery/core/RecoveryCertificate.kt index a7c79343f..e47e5d6df 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/recovery/core/RecoveryCertificate.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/recovery/core/RecoveryCertificate.kt @@ -1,6 +1,7 @@ package de.rki.coronawarnapp.covidcertificate.recovery.core import de.rki.coronawarnapp.covidcertificate.common.certificate.CwaCovidCertificate +import de.rki.coronawarnapp.covidcertificate.common.certificate.RecoveryDccV1 import de.rki.coronawarnapp.covidcertificate.common.repository.RecoveryCertificateContainerId import org.joda.time.LocalDate @@ -9,4 +10,6 @@ interface RecoveryCertificate : CwaCovidCertificate { val testedPositiveOn: LocalDate val validFrom: LocalDate val validUntil: LocalDate + + override val rawCertificate: RecoveryDccV1 } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/recovery/core/storage/RecoveryCertificateContainer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/recovery/core/storage/RecoveryCertificateContainer.kt index 02e1191bf..580d5a548 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/recovery/core/storage/RecoveryCertificateContainer.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/recovery/core/storage/RecoveryCertificateContainer.kt @@ -51,6 +51,9 @@ data class RecoveryCertificateContainer( override val containerId: RecoveryCertificateContainerId get() = this@RecoveryCertificateContainer.containerId + override val rawCertificate: RecoveryDccV1 + get() = certificate + override val personIdentifier: CertificatePersonIdentifier get() = certificate.personIdentifier diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificate.kt index a26e13150..91aa04767 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificate.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/TestCertificate.kt @@ -1,6 +1,7 @@ package de.rki.coronawarnapp.covidcertificate.test.core import de.rki.coronawarnapp.covidcertificate.common.certificate.CwaCovidCertificate +import de.rki.coronawarnapp.covidcertificate.common.certificate.TestDccV1 import de.rki.coronawarnapp.covidcertificate.common.repository.TestCertificateContainerId import org.joda.time.Instant @@ -28,4 +29,6 @@ interface TestCertificate : CwaCovidCertificate { val registeredAt: Instant val isUpdatingData: Boolean val isCertificateRetrievalPending: Boolean + + override val rawCertificate: TestDccV1 } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateContainer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateContainer.kt index 198a497ed..c58017f61 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateContainer.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/test/core/storage/TestCertificateContainer.kt @@ -3,6 +3,7 @@ package de.rki.coronawarnapp.covidcertificate.test.core.storage import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier import de.rki.coronawarnapp.covidcertificate.common.certificate.DccQrCodeExtractor import de.rki.coronawarnapp.covidcertificate.common.certificate.DccV1Parser +import de.rki.coronawarnapp.covidcertificate.common.certificate.TestDccV1 import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString import de.rki.coronawarnapp.covidcertificate.common.repository.CertificateRepoContainer import de.rki.coronawarnapp.covidcertificate.common.repository.TestCertificateContainerId @@ -73,6 +74,9 @@ data class TestCertificateContainer( override val containerId: TestCertificateContainerId get() = this@TestCertificateContainer.containerId + override val rawCertificate: TestDccV1 + get() = certificate + override val personIdentifier: CertificatePersonIdentifier get() = certificate.personIdentifier diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationCertificate.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationCertificate.kt index 4cafa9cd7..39ae0f2a9 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationCertificate.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/VaccinationCertificate.kt @@ -1,6 +1,7 @@ package de.rki.coronawarnapp.covidcertificate.vaccination.core import de.rki.coronawarnapp.covidcertificate.common.certificate.CwaCovidCertificate +import de.rki.coronawarnapp.covidcertificate.common.certificate.VaccinationDccV1 import de.rki.coronawarnapp.covidcertificate.common.repository.VaccinationCertificateContainerId import org.joda.time.LocalDate @@ -15,5 +16,7 @@ interface VaccinationCertificate : CwaCovidCertificate { val doseNumber: Int val totalSeriesOfDoses: Int + override val rawCertificate: VaccinationDccV1 + val isFinalShot get() = doseNumber == totalSeriesOfDoses } diff --git a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainer.kt b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainer.kt index 374607f40..d2b5ba3b3 100644 --- a/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainer.kt +++ b/Corona-Warn-App/src/main/java/de/rki/coronawarnapp/covidcertificate/vaccination/core/repository/storage/VaccinationContainer.kt @@ -69,6 +69,9 @@ data class VaccinationContainer internal constructor( override val containerId: VaccinationCertificateContainerId get() = this@VaccinationContainer.containerId + override val rawCertificate: VaccinationDccV1 + get() = certificate + override val personIdentifier: CertificatePersonIdentifier get() = certificate.personIdentifier diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesProviderTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesProviderTest.kt index 33fe14aed..ba2bd4596 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesProviderTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/core/PersonCertificatesProviderTest.kt @@ -19,6 +19,7 @@ import io.mockk.verify import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runBlockingTest +import org.joda.time.Instant import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import testhelpers.BaseTest @@ -34,18 +35,21 @@ class PersonCertificatesProviderTest : BaseTest() { private val vaccinatedPersonACertificate1 = mockk<VaccinationCertificate>().apply { every { personIdentifier } returns identifierA + every { issuedAt } returns Instant.EPOCH } private val vaccinatedPersonA = mockk<VaccinatedPerson>().apply { every { vaccinationCertificates } returns setOf(vaccinatedPersonACertificate1) } private val testWrapperACertificate = mockk<TestCertificate>().apply { every { personIdentifier } returns identifierA + every { issuedAt } returns Instant.EPOCH } private val testWrapperA = mockk<TestCertificateWrapper>().apply { every { testCertificate } returns testWrapperACertificate } private val recoveryWrapperACertificate = mockk<RecoveryCertificate>().apply { every { personIdentifier } returns identifierA + every { issuedAt } returns Instant.EPOCH } private val recoveryWrapperA = mockk<RecoveryCertificateWrapper>().apply { every { testCertificate } returns recoveryWrapperACertificate diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/ui/overview/PersonCertificatesData.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/ui/overview/PersonCertificatesData.kt index 2c950ba42..7725b08c8 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/ui/overview/PersonCertificatesData.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/ui/overview/PersonCertificatesData.kt @@ -1,10 +1,12 @@ package de.rki.coronawarnapp.covidcertificate.person.ui.overview import de.rki.coronawarnapp.covidcertificate.common.certificate.CertificatePersonIdentifier +import de.rki.coronawarnapp.covidcertificate.common.certificate.TestDccV1 import de.rki.coronawarnapp.covidcertificate.common.qrcode.QrCodeString import de.rki.coronawarnapp.covidcertificate.common.repository.TestCertificateContainerId import de.rki.coronawarnapp.covidcertificate.person.core.PersonCertificates import de.rki.coronawarnapp.covidcertificate.test.core.TestCertificate +import io.mockk.mockk import org.joda.time.Instant import org.joda.time.LocalDate import java.util.UUID @@ -72,4 +74,7 @@ fun testCertificate( override val certificateIssuer: String = "certificateIssuer" override val certificateCountry: String = "certificateCountry" override val certificateId: String = "certificateId" + + override val rawCertificate: TestDccV1 + get() = mockk() } diff --git a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/ui/overview/PersonOverviewViewModelTest.kt b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/ui/overview/PersonOverviewViewModelTest.kt index c7b9d15b8..0a0a69a9d 100644 --- a/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/ui/overview/PersonOverviewViewModelTest.kt +++ b/Corona-Warn-App/src/test/java/de/rki/coronawarnapp/covidcertificate/person/ui/overview/PersonOverviewViewModelTest.kt @@ -20,6 +20,7 @@ import io.mockk.impl.annotations.MockK import io.mockk.just import io.mockk.mockk import io.mockk.mockkStatic +import io.mockk.spyk import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flowOf import org.junit.jupiter.api.BeforeEach @@ -46,6 +47,7 @@ class PersonOverviewViewModelTest : BaseTest() { fun setup() { MockKAnnotations.init(this, true) mockkStatic("de.rki.coronawarnapp.contactdiary.util.ContactDiaryExtensionsKt") + coEvery { testCertificateRepository.refresh(any()) } returns setOf(refreshResult) coEvery { qrCodeGenerator.createQrCode(any(), any(), any(), any(), any()) } returns mockk() every { personCertificatesProvider.personCertificates } returns emptyFlow() @@ -94,7 +96,13 @@ class PersonOverviewViewModelTest : BaseTest() { @Test fun `Sorting - List has pending certificate`() { every { personCertificatesProvider.personCertificates } returns - flowOf(PersonCertificatesData.certificatesWithPending) + PersonCertificatesData.certificatesWithPending + .map { + spyk(it).apply { + every { highestPriorityCertificate } returns certificates.first() + } + }.run { flowOf(this.toSet()) } + instance.personCertificates.getOrAwaitValue().apply { (get(0) as CovidTestCertificatePendingCard.Item).apply { certificate.fullName shouldBe "Max Mustermann" } (get(1) as PersonCertificateCard.Item).apply { certificate.fullName shouldBe "Zeebee" } @@ -105,7 +113,13 @@ class PersonOverviewViewModelTest : BaseTest() { @Test fun `Sorting - List has pending & updating certificate`() { every { personCertificatesProvider.personCertificates } returns - flowOf(PersonCertificatesData.certificatesWithUpdating) + PersonCertificatesData.certificatesWithUpdating + .map { + spyk(it).apply { + every { highestPriorityCertificate } returns certificates.first() + } + }.run { flowOf(this.toSet()) } + instance.personCertificates.getOrAwaitValue().apply { (get(0) as CovidTestCertificatePendingCard.Item).apply { certificate.fullName shouldBe "Max Mustermann" } (get(1) as PersonCertificateCard.Item).apply { certificate.fullName shouldBe "Zeebee" } @@ -116,7 +130,13 @@ class PersonOverviewViewModelTest : BaseTest() { @Test fun `Sorting - List has no CWA user`() { every { personCertificatesProvider.personCertificates } returns - flowOf(PersonCertificatesData.certificatesWithoutCwaUser) + PersonCertificatesData.certificatesWithoutCwaUser + .map { + spyk(it).apply { + every { highestPriorityCertificate } returns certificates.first() + } + }.run { flowOf(this.toSet()) } + instance.personCertificates.getOrAwaitValue().apply { (get(0) as PersonCertificateCard.Item).apply { certificate.fullName shouldBe "Andrea Schneider" } (get(1) as PersonCertificateCard.Item).apply { certificate.fullName shouldBe "Erika Musterfrau" } @@ -127,7 +147,13 @@ class PersonOverviewViewModelTest : BaseTest() { @Test fun `Sorting - List has CWA user`() { every { personCertificatesProvider.personCertificates } returns - flowOf(PersonCertificatesData.certificatesWithCwaUser) + PersonCertificatesData.certificatesWithCwaUser + .map { + spyk(it).apply { + every { highestPriorityCertificate } returns certificates.first() + } + }.run { flowOf(this.toSet()) } + instance.personCertificates.getOrAwaitValue().apply { (get(0) as PersonCertificateCard.Item).apply { certificate.fullName shouldBe "Zeebee" } // CWA user (get(1) as PersonCertificateCard.Item).apply { certificate.fullName shouldBe "Andrea Schneider" } -- GitLab