Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test: Issuance feature interactors tests #212

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ import eu.europa.ec.analyticslogic.controller.AnalyticsController
import eu.europa.ec.assemblylogic.di.setupKoin
import eu.europa.ec.corelogic.config.WalletCoreConfig
import eu.europa.ec.eudi.wallet.EudiWallet
import eu.europa.ec.resourceslogic.theme.ThemeManager
import eu.europa.ec.resourceslogic.theme.templates.ThemeDimensTemplate
import eu.europa.ec.resourceslogic.theme.values.ThemeColors
import eu.europa.ec.resourceslogic.theme.values.ThemeShapes
import eu.europa.ec.resourceslogic.theme.values.ThemeTypography
import org.koin.android.ext.android.inject

class Application : Application() {
Expand All @@ -38,27 +33,12 @@ class Application : Application() {
setupKoin()
initializeReporting()
initializeEudiWallet()
initializeTheme()
}

private fun initializeReporting() {
analyticsController.initialize(this)
}

private fun initializeTheme() {
ThemeManager.Builder()
.withLightColors(ThemeColors.lightColors)
.withDarkColors(ThemeColors.darkColors)
.withTypography(ThemeTypography.typo)
.withShapes(ThemeShapes.shapes)
.withDimensions(
ThemeDimensTemplate(
screenPadding = 10.0
)
)
.build()
}

private fun initializeEudiWallet() {
EudiWallet.init(
applicationContext,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,13 @@ import eu.europa.ec.eudi.iso18013.transfer.DocItem
import eu.europa.ec.eudi.iso18013.transfer.DocRequest
import eu.europa.ec.eudi.iso18013.transfer.ReaderAuth
import eu.europa.ec.eudi.iso18013.transfer.RequestDocument
import eu.europa.ec.eudi.wallet.issue.openid4vci.Offer.TxCodeSpec
import eu.europa.ec.uilogic.component.AppIcons
import eu.europa.ec.uilogic.component.InfoTextWithNameAndImageData
import eu.europa.ec.uilogic.component.InfoTextWithNameAndValueData
import eu.europa.ec.uilogic.config.ConfigNavigation
import eu.europa.ec.uilogic.config.NavigationType
import eu.europa.ec.uilogic.navigation.DashboardScreens

@VisibleForTesting(otherwise = VisibleForTesting.NONE)
object TestsData {
Expand Down Expand Up @@ -78,8 +82,21 @@ object TestsData {
const val mockedDocumentHasExpired = false
const val mockedUserAuthentication = false
const val mockedVerifierName = "EUDIW Verifier"
const val mockedIssuerName = "EUDIW Issuer"
const val mockedRequestRequiredFieldsTitle = "Verification Data"
const val mockedRequestElementIdentifierNotAvailable = "Not available"
const val mockedOfferedDocumentName = "Offered Document"
const val mockedOfferedDocumentDocType = "mocked_offered_document_doc_type"
const val mockedTxCodeSpecFourDigits = 4
const val mockedSuccessTitle = "Success title"
const val mockedSuccessSubtitle = "Success subtitle"
const val mockedSuccessContentDescription = "Content description"
const val mockedIssuanceErrorMessage = "Issuance error message"
const val mockedInvalidCodeFormatMessage = "Invalid code format message"
const val mockedWalletActivationErrorMessage = "Wallet activation error message"
const val mockedPrimaryButtonText = "Primary button text"
const val mockedRouteArguments = "mockedRouteArguments"
const val mockedTxCode = "mockedTxCode"

const val mockedPidDocType = "eu.europa.ec.eudi.pid.1"
const val mockedPidNameSpace = "eu.europa.ec.eudi.pid.1"
Expand Down Expand Up @@ -476,6 +493,24 @@ object TestsData {
available = true
)

val mockedConfigNavigationTypePop = ConfigNavigation(navigationType = NavigationType.Pop)
val mockedConfigNavigationTypePush = ConfigNavigation(
navigationType = NavigationType.PushRoute(
route = DashboardScreens.Dashboard.screenRoute
)
)
val mockedConfigNavigationTypePopToScreen = ConfigNavigation(
navigationType = NavigationType.PopTo(
screen = DashboardScreens.Dashboard
)
)

val mockedOfferTxCodeSpecFourDigits =
TxCodeSpec(
inputMode = TxCodeSpec.InputMode.NUMERIC,
length = mockedTxCodeSpecFourDigits
)

val mockedOptionalFieldsForPidWithBasicFields = listOf(
TestFieldUi(
elementIdentifier = "family_name",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class AddDocumentViewModel(
@InjectedParam private val flowType: IssuanceFlowUiConfig,
) : MviViewModel<Event, State, Effect>() {

var issuanceJob: Job? = null
private var issuanceJob: Job? = null

override fun setInitialState(): State = State(
navigatableAction = getNavigatableAction(flowType),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,30 @@ import eu.europa.ec.authenticationlogic.controller.authentication.BiometricsAvai
import eu.europa.ec.authenticationlogic.controller.authentication.DeviceAuthenticationResult
import eu.europa.ec.authenticationlogic.model.BiometricCrypto
import eu.europa.ec.commonfeature.config.IssuanceFlowUiConfig
import eu.europa.ec.commonfeature.config.SuccessUIConfig
import eu.europa.ec.commonfeature.interactor.DeviceAuthenticationInteractor
import eu.europa.ec.commonfeature.util.TestsData.mockedAgeOptionItemUi
import eu.europa.ec.commonfeature.util.TestsData.mockedConfigNavigationTypePopToScreen
import eu.europa.ec.commonfeature.util.TestsData.mockedConfigNavigationTypePush
import eu.europa.ec.commonfeature.util.TestsData.mockedMdlOptionItemUi
import eu.europa.ec.commonfeature.util.TestsData.mockedPhotoIdOptionItemUi
import eu.europa.ec.commonfeature.util.TestsData.mockedPidId
import eu.europa.ec.commonfeature.util.TestsData.mockedPidOptionItemUi
import eu.europa.ec.commonfeature.util.TestsData.mockedPrimaryButtonText
import eu.europa.ec.commonfeature.util.TestsData.mockedRouteArguments
import eu.europa.ec.commonfeature.util.TestsData.mockedSampleDataOptionItemUi
import eu.europa.ec.commonfeature.util.TestsData.mockedSuccessContentDescription
import eu.europa.ec.commonfeature.util.TestsData.mockedSuccessSubtitle
import eu.europa.ec.commonfeature.util.TestsData.mockedSuccessTitle
import eu.europa.ec.commonfeature.util.TestsData.mockedUriPath1
import eu.europa.ec.corelogic.controller.AddSampleDataPartialState
import eu.europa.ec.corelogic.controller.IssuanceMethod
import eu.europa.ec.corelogic.controller.IssueDocumentPartialState
import eu.europa.ec.corelogic.controller.WalletCoreDocumentsController
import eu.europa.ec.corelogic.model.DocumentIdentifier
import eu.europa.ec.resourceslogic.R
import eu.europa.ec.resourceslogic.provider.ResourceProvider
import eu.europa.ec.resourceslogic.theme.values.ThemeColors
import eu.europa.ec.testfeature.MockResourceProviderForStringCalls.mockDocumentTypeUiToUiNameCall
import eu.europa.ec.testfeature.mockedExceptionWithMessage
import eu.europa.ec.testfeature.mockedExceptionWithNoMessage
Expand All @@ -43,6 +54,7 @@ import eu.europa.ec.testlogic.extension.runFlowTest
import eu.europa.ec.testlogic.extension.runTest
import eu.europa.ec.testlogic.extension.toFlow
import eu.europa.ec.testlogic.rule.CoroutineTestRule
import eu.europa.ec.uilogic.component.AppIcons
import eu.europa.ec.uilogic.serializer.UiSerializer
import junit.framework.TestCase.assertEquals
import org.junit.After
Expand Down Expand Up @@ -296,7 +308,7 @@ class TestAddDocumentInteractor {
// Case 1 Expected Result:
// deviceAuthenticationInteractor.authenticateWithBiometrics called once.
@Test
fun `Given case 1, When handleUserAuth is called, Then Case 1 expected result is returned`() {
fun `Given Case 1, When handleUserAuth is called, Then Case 1 expected result is returned`() {
// Given
mockBiometricsAvailabilityResponse(
response = BiometricsAvailability.CanAuthenticate
Expand All @@ -321,7 +333,7 @@ class TestAddDocumentInteractor {
// Case 2 Expected Result:
// deviceAuthenticationInteractor.authenticateWithBiometrics called once.
@Test
fun `Given case 2, When handleUserAuth is called, Then Case 2 expected result is returned`() {
fun `Given Case 2, When handleUserAuth is called, Then Case 2 expected result is returned`() {
// Given
mockBiometricsAvailabilityResponse(
response = BiometricsAvailability.NonEnrolled
Expand All @@ -346,7 +358,7 @@ class TestAddDocumentInteractor {
// Case 3 Expected Result:
// resultHandler.onAuthenticationFailure called once.
@Test
fun `Given case 3, When handleUserAuth is called, Then Case 3 expected result is returned`() {
fun `Given Case 3, When handleUserAuth is called, Then Case 3 expected result is returned`() {
// Given
val mockedOnAuthenticationFailure: () -> Unit = {}
whenever(resultHandler.onAuthenticationFailure)
Expand All @@ -371,6 +383,102 @@ class TestAddDocumentInteractor {
}
//endregion

//region buildGenericSuccessRouteForDeferred

// Case 1:
// 1. ConfigNavigation with NavigationType.PushRoute
// 2. string resources mocked
@Test
fun `Given Case 1, When buildGenericSuccessRouteForDeferred is called, Then the expected string result is returned`() {
// Given
mockDocumentIssuanceStrings()

val config = SuccessUIConfig(
headerConfig = mockedTripleObject.first,
content = resourceProvider.getString(R.string.issuance_add_document_deferred_success_subtitle),
imageConfig = mockedTripleObject.second,
buttonConfig = listOf(
SuccessUIConfig.ButtonConfig(
text = mockedTripleObject.third,
style = SuccessUIConfig.ButtonConfig.Style.PRIMARY,
navigation = mockedConfigNavigationTypePush
)
),
onBackScreenToNavigate = mockedConfigNavigationTypePush
)

whenever(
uiSerializer.toBase64(
model = config,
parser = SuccessUIConfig.Parser
)
).thenReturn(mockedRouteArguments)

val flowType = IssuanceFlowUiConfig.NO_DOCUMENT

// When
val result = interactor.buildGenericSuccessRouteForDeferred(flowType = flowType)

// Then
val expectedResult = "SUCCESS?successConfig=$mockedRouteArguments"
assertEquals(expectedResult, result)
}

// Case 2:
// 1. ConfigNavigation with NavigationType.PopRoute
// 2. string resources mocked
@Test
fun `When buildGenericSuccessRouteForDeferred (PopRoute) is called, then the expected string result is returned`() {
// Given
mockDocumentIssuanceStrings()

val config = SuccessUIConfig(
headerConfig = mockedTripleObject.first,
content = resourceProvider.getString(R.string.issuance_add_document_deferred_success_subtitle),
imageConfig = mockedTripleObject.second,
buttonConfig = listOf(
SuccessUIConfig.ButtonConfig(
text = mockedTripleObject.third,
style = SuccessUIConfig.ButtonConfig.Style.PRIMARY,
navigation = mockedConfigNavigationTypePopToScreen
)
),
onBackScreenToNavigate = mockedConfigNavigationTypePopToScreen
)

whenever(
uiSerializer.toBase64(
model = config,
parser = SuccessUIConfig.Parser
)
).thenReturn(mockedRouteArguments)

val flowType = IssuanceFlowUiConfig.EXTRA_DOCUMENT

// When
val result = interactor.buildGenericSuccessRouteForDeferred(flowType = flowType)

// Then
val expectedResult = "SUCCESS?successConfig=$mockedRouteArguments"
assertEquals(expectedResult, result)
}
//endregion

//region resumeOpenId4VciWithAuthorization

// Case of resumeOpenId4VciWithAuthorization being called on the interactor
// the expected result is the resumeOpenId4VciWithAuthorization function to be executed on
// the walletCoreDocumentsController
@Test
fun `When interactor resumeOpenId4VciWithAuthorization is called, Then resumeOpenId4VciWithAuthorization should be invoked on the controller`() {
// When
interactor.resumeOpenId4VciWithAuthorization(mockedUriPath1)

verify(walletCoreDocumentsController, times(1))
.resumeOpenId4VciWithAuthorization(mockedUriPath1)
}
//endregion

//region helper functions
private fun mockBiometricsAvailabilityResponse(response: BiometricsAvailability) {
whenever(deviceAuthenticationInteractor.getBiometricsAvailability(listener = any()))
Expand All @@ -379,5 +487,34 @@ class TestAddDocumentInteractor {
bioAvailability(response)
}
}

private fun mockDocumentIssuanceStrings() {
whenever(resourceProvider.getString(R.string.issuance_add_document_deferred_success_title))
.thenReturn(mockedSuccessTitle)
whenever(resourceProvider.getString(R.string.issuance_add_document_deferred_success_primary_button_text))
.thenReturn(mockedPrimaryButtonText)
whenever(resourceProvider.getString(AppIcons.ClockTimer.contentDescriptionId))
.thenReturn(mockedSuccessContentDescription)
whenever(resourceProvider.getString(R.string.issuance_add_document_deferred_success_subtitle))
.thenReturn(mockedSuccessSubtitle)
}
//endregion

//region mocked objects
private val mockedTripleObject by lazy {
Triple(
first = SuccessUIConfig.HeaderConfig(
title = resourceProvider.getString(R.string.issuance_add_document_deferred_success_title),
color = ThemeColors.warning
),
second = SuccessUIConfig.ImageConfig(
type = SuccessUIConfig.ImageConfig.Type.DRAWABLE,
drawableRes = AppIcons.ClockTimer.resourceId,
tint = ThemeColors.warning,
contentDescription = resourceProvider.getString(AppIcons.ClockTimer.contentDescriptionId)
),
third = resourceProvider.getString(R.string.issuance_add_document_deferred_success_primary_button_text)
)
}
//endregion
}
Loading
Loading