-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #199 from niscy-eudiw/test/proximity_feature_inter…
…actors_unit_tests Test: Proximity feature interactors tests
- Loading branch information
Showing
5 changed files
with
357 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
323 changes: 323 additions & 0 deletions
323
.../src/test/java/eu/europa/ec/proximityfeature/interactor/TestProximityLoadingInteractor.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,323 @@ | ||
/* | ||
* Copyright (c) 2023 European Commission | ||
* | ||
* Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European | ||
* Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work | ||
* except in compliance with the Licence. | ||
* | ||
* You may obtain a copy of the Licence at: | ||
* https://joinup.ec.europa.eu/software/page/eupl | ||
* | ||
* Unless required by applicable law or agreed to in writing, software distributed under | ||
* the Licence is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF | ||
* ANY KIND, either express or implied. See the Licence for the specific language | ||
* governing permissions and limitations under the Licence. | ||
*/ | ||
|
||
package eu.europa.ec.proximityfeature.interactor | ||
|
||
import android.content.Context | ||
import eu.europa.ec.authenticationlogic.controller.authentication.BiometricsAvailability | ||
import eu.europa.ec.authenticationlogic.controller.authentication.DeviceAuthenticationResult | ||
import eu.europa.ec.authenticationlogic.model.BiometricCrypto | ||
import eu.europa.ec.commonfeature.interactor.DeviceAuthenticationInteractor | ||
import eu.europa.ec.commonfeature.util.TestsData.mockedUriPath1 | ||
import eu.europa.ec.corelogic.controller.WalletCorePartialState | ||
import eu.europa.ec.corelogic.controller.WalletCorePresentationController | ||
import eu.europa.ec.testfeature.mockedPlainFailureMessage | ||
import eu.europa.ec.testlogic.extension.expectNoEvents | ||
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 junit.framework.TestCase.assertEquals | ||
import org.junit.After | ||
import org.junit.Before | ||
import org.junit.Rule | ||
import org.junit.Test | ||
import org.mockito.Mock | ||
import org.mockito.MockitoAnnotations | ||
import org.mockito.kotlin.any | ||
import org.mockito.kotlin.times | ||
import org.mockito.kotlin.verify | ||
import org.mockito.kotlin.whenever | ||
import java.net.URI | ||
|
||
class TestProximityLoadingInteractor { | ||
|
||
@get:Rule | ||
val coroutineRule = CoroutineTestRule() | ||
|
||
@Mock | ||
private lateinit var walletCorePresentationController: WalletCorePresentationController | ||
|
||
@Mock | ||
private lateinit var deviceAuthenticationInteractor: DeviceAuthenticationInteractor | ||
|
||
@Mock | ||
private lateinit var resultHandler: DeviceAuthenticationResult | ||
|
||
@Mock | ||
private lateinit var context: Context | ||
|
||
private lateinit var interactor: ProximityLoadingInteractor | ||
|
||
private lateinit var crypto: BiometricCrypto | ||
|
||
private lateinit var closeable: AutoCloseable | ||
|
||
@Before | ||
fun before() { | ||
closeable = MockitoAnnotations.openMocks(this) | ||
|
||
interactor = ProximityLoadingInteractorImpl( | ||
walletCorePresentationController = walletCorePresentationController, | ||
deviceAuthenticationInteractor = deviceAuthenticationInteractor | ||
) | ||
|
||
crypto = BiometricCrypto(cryptoObject = null) | ||
} | ||
|
||
@After | ||
fun after() { | ||
closeable.close() | ||
} | ||
|
||
//region observeResponse | ||
// Case 1 | ||
// 1. walletCorePresentationController.events emits: | ||
// TransferEventPartialState.Failure, with an error message. | ||
|
||
// Case 1 Expected Result: | ||
// ProximityLoadingObserveResponsePartialState.Failure state, with the same error message. | ||
@Test | ||
fun `Given Case 1, When observeResponse is called, Then Case 1 Expected Result is returned`() { | ||
coroutineRule.runTest { | ||
// Given | ||
mockWalletCorePresentationControllerEventEmission( | ||
event = WalletCorePartialState.Failure( | ||
error = mockedPlainFailureMessage | ||
) | ||
) | ||
|
||
// When | ||
interactor.observeResponse() | ||
.runFlowTest { | ||
// Then | ||
assertEquals( | ||
ProximityLoadingObserveResponsePartialState.Failure( | ||
error = mockedPlainFailureMessage | ||
), | ||
awaitItem() | ||
) | ||
} | ||
} | ||
} | ||
|
||
// Case 2 | ||
// 1. walletCorePresentationController.events emits: | ||
// WalletCorePartialState.Success | ||
|
||
// Case 2 Expected Result: | ||
// PresentationLoadingObserveResponsePartialState.Success. | ||
@Test | ||
fun `Given Case 2, When observeResponse is called, Then Case 2 Expected Result is returned`() { | ||
coroutineRule.runTest { | ||
// Given | ||
mockWalletCorePresentationControllerEventEmission( | ||
event = WalletCorePartialState.Success | ||
) | ||
|
||
// When | ||
interactor.observeResponse() | ||
.runFlowTest { | ||
val expectedResult = ProximityLoadingObserveResponsePartialState.Success | ||
// Then | ||
assertEquals( | ||
expectedResult, | ||
awaitItem() | ||
) | ||
} | ||
} | ||
} | ||
|
||
// Case 3: | ||
// 1. walletCorePresentationController.events emits an event that we do not want to react to, i.e: | ||
// TransferEventPartialState.Redirect | ||
|
||
// Case 3 Expected Result is that no events are emitted | ||
@Test | ||
fun `Given Case 3, When observeResponse is called, Then Case 3 Expected Result is returned`() { | ||
coroutineRule.runTest { | ||
// Given | ||
mockEmissionOfIntentionallyNotHandledEvent() | ||
|
||
// When | ||
interactor.observeResponse() | ||
.expectNoEvents() | ||
} | ||
} | ||
|
||
// Case 4: | ||
// 1. walletCorePresentationController.events emits: | ||
// WalletCorePartialState.UserAuthenticationRequired. | ||
|
||
// Case 4 Expected Result: | ||
// PresentationLoadingObserveResponsePartialState.UserAuthenticationRequired. | ||
@Test | ||
fun `Given Case 4, When observeResponse is called, Then Case 4 Expected Result is returned`() { | ||
coroutineRule.runTest { | ||
mockWalletCorePresentationControllerEventEmission( | ||
event = WalletCorePartialState.UserAuthenticationRequired( | ||
crypto = crypto, | ||
resultHandler = resultHandler | ||
) | ||
) | ||
|
||
// When | ||
interactor.observeResponse() | ||
.runFlowTest { | ||
val expectedResult = | ||
ProximityLoadingObserveResponsePartialState.UserAuthenticationRequired( | ||
crypto = crypto, | ||
resultHandler = resultHandler | ||
) | ||
assertEquals(expectedResult, awaitItem()) | ||
} | ||
} | ||
} | ||
//endregion | ||
|
||
//region handleUserAuthentication | ||
// | ||
// Case 1: | ||
// 1. deviceAuthenticationInteractor.getBiometricsAvailability returns: | ||
// BiometricsAvailability.CanAuthenticate | ||
|
||
// Case 1 Expected Result: | ||
// deviceAuthenticationInteractor.authenticateWithBiometrics called once. | ||
@Test | ||
fun `Given case 1, When handleUserAuthentication is called, Then Case 1 Expected Result is returned`() { | ||
// Given | ||
mockBiometricsAvailabilityResponse( | ||
response = BiometricsAvailability.CanAuthenticate | ||
) | ||
|
||
// When | ||
interactor.handleUserAuthentication( | ||
context = context, | ||
crypto = crypto, | ||
resultHandler = resultHandler | ||
) | ||
|
||
// Then | ||
verify(deviceAuthenticationInteractor, times(1)) | ||
.authenticateWithBiometrics(context, crypto, resultHandler) | ||
} | ||
|
||
// Case 2: | ||
// 1. deviceAuthenticationInteractor.getBiometricsAvailability returns: | ||
// BiometricsAvailability.NonEnrolled | ||
|
||
// Case 2 Expected Result: | ||
// deviceAuthenticationInteractor.authenticateWithBiometrics called once. | ||
@Test | ||
fun `Given case 2, When handleUserAuthentication is called, Then Case 2 expected result is returned`() { | ||
// Given | ||
mockBiometricsAvailabilityResponse( | ||
response = BiometricsAvailability.NonEnrolled | ||
) | ||
|
||
// When | ||
interactor.handleUserAuthentication( | ||
context = context, | ||
crypto = crypto, | ||
resultHandler = resultHandler | ||
) | ||
|
||
// Then | ||
verify(deviceAuthenticationInteractor, times(1)) | ||
.authenticateWithBiometrics(context, crypto, resultHandler) | ||
} | ||
|
||
// Case 3: | ||
// 1. deviceAuthenticationInteractor.getBiometricsAvailability returns: | ||
// BiometricsAvailability.Failure with message | ||
|
||
// Case 3 Expected Result: | ||
// resultHandler.onAuthenticationFailure called once. | ||
@Test | ||
fun `Given case 3, When handleUserAuthentication is called, Then Case 3 expected result is returned`() { | ||
// Given | ||
mockBiometricsAvailabilityResponse( | ||
response = BiometricsAvailability.Failure( | ||
errorMessage = mockedPlainFailureMessage | ||
) | ||
) | ||
val mockedOnAuthenticationFailure: () -> Unit = {} | ||
whenever(resultHandler.onAuthenticationFailure) | ||
.thenReturn(mockedOnAuthenticationFailure) | ||
|
||
// When | ||
interactor.handleUserAuthentication( | ||
context = context, | ||
crypto = crypto, | ||
resultHandler = resultHandler | ||
) | ||
|
||
// Then | ||
verify(resultHandler, times(1)) | ||
.onAuthenticationFailure | ||
} | ||
|
||
//endregion | ||
|
||
//region stopPresentation | ||
|
||
@Test | ||
fun `when interactor stopPresentation is called then it delegates to walletCoreInteractor stopPresentation`() { | ||
// When | ||
interactor.stopPresentation() | ||
|
||
// Then | ||
verify(walletCorePresentationController, times(1)) | ||
.stopPresentation() | ||
} | ||
|
||
//endregion | ||
|
||
//region verifierName | ||
|
||
@Test | ||
fun `when interactor verifierName is called, then verifierName should be invoked on the controller`() { | ||
// When | ||
interactor.verifierName | ||
|
||
// Then | ||
verify(walletCorePresentationController, times(1)) | ||
.verifierName | ||
} | ||
|
||
//endregion | ||
|
||
//region helper functions | ||
private fun mockWalletCorePresentationControllerEventEmission(event: WalletCorePartialState) { | ||
whenever(walletCorePresentationController.observeSentDocumentsRequest()) | ||
.thenReturn(event.toFlow()) | ||
} | ||
|
||
private fun mockBiometricsAvailabilityResponse(response: BiometricsAvailability) { | ||
whenever(deviceAuthenticationInteractor.getBiometricsAvailability(listener = any())) | ||
.thenAnswer { | ||
val bioAvailability = it.getArgument<(BiometricsAvailability) -> Unit>(0) | ||
bioAvailability(response) | ||
} | ||
} | ||
|
||
private fun mockEmissionOfIntentionallyNotHandledEvent() { | ||
whenever(walletCorePresentationController.observeSentDocumentsRequest()).thenReturn( | ||
WalletCorePartialState.Redirect(uri = URI(mockedUriPath1)).toFlow() | ||
) | ||
} | ||
//endregion | ||
} |
Oops, something went wrong.