Merge "[BiometricsV2] Refactor EnrollIntroViewModel" into main

This commit is contained in:
Treehugger Robot
2023-08-07 05:22:36 +00:00
committed by Android (Google) Code Review
6 changed files with 580 additions and 607 deletions

View File

@@ -1,328 +0,0 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.biometrics2.ui.viewmodel;
import static android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL;
import static com.android.settings.biometrics2.ui.model.FingerprintEnrollable.FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX;
import static com.android.settings.biometrics2.ui.model.FingerprintEnrollable.FINGERPRINT_ENROLLABLE_OK;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH;
import static com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroViewModel.FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL;
import static com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newAllFalseRequest;
import static com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwDeferredRequest;
import static com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwPortalRequest;
import static com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwRequest;
import static com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwSuggestedActionFlowRequest;
import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository;
import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupFingerprintEnrolledFingerprints;
import static com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupSuwMaxFingerprintsEnrollable;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import android.app.Application;
import android.content.res.Resources;
import android.hardware.fingerprint.FingerprintManager;
import androidx.annotation.NonNull;
import androidx.lifecycle.MutableLiveData;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settings.biometrics2.data.repository.FingerprintRepository;
import com.android.settings.biometrics2.ui.model.EnrollmentRequest;
import com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus;
import com.android.settings.testutils.InstantTaskExecutorRule;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@RunWith(AndroidJUnit4.class)
public class FingerprintEnrollIntroViewModelTest {
private static final int TEST_USER_ID = 33;
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
@Rule public final InstantTaskExecutorRule mTaskExecutorRule = new InstantTaskExecutorRule();
@Mock private Resources mResources;
@Mock private FingerprintManager mFingerprintManager;
private Application mApplication;
private FingerprintEnrollIntroViewModel newFingerprintEnrollIntroViewModel(
@NonNull FingerprintRepository fingerprintRepository,
@NonNull EnrollmentRequest enrollmentRequest) {
final FingerprintEnrollIntroViewModel viewModel =
new FingerprintEnrollIntroViewModel(mApplication, fingerprintRepository,
enrollmentRequest, TEST_USER_ID);
// MediatorLiveData won't update itself unless observed
viewModel.getPageStatusLiveData().observeForever(event -> {});
return viewModel;
}
@Before
public void setUp() {
mApplication = ApplicationProvider.getApplicationContext();
}
@Test
public void testPageStatusLiveDataDefaultValue() {
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newAllFalseRequest(mApplication));
final FingerprintEnrollIntroStatus status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.hasScrollToBottom()).isFalse();
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_OK);
}
@Test
public void testPageStatusLiveDataRefreshWhenRefetch() {
final FingerprintRepository repository = newFingerprintRepository(mFingerprintManager,
TYPE_UDFPS_OPTICAL, 1);
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
repository,
newAllFalseRequest(mApplication));
FingerprintEnrollIntroStatus status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.hasScrollToBottom()).isFalse();
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_OK);
setupFingerprintEnrolledFingerprints(mFingerprintManager, TEST_USER_ID, 1);
// Refetch PageStatusLiveData
status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.hasScrollToBottom()).isFalse();
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX);
}
@Test
public void testClearActionLiveData() {
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newAllFalseRequest(mApplication));
final MutableLiveData<Integer> actionLiveData =
(MutableLiveData<Integer>) viewModel.getActionLiveData();
actionLiveData.postValue(1);
assertThat(actionLiveData.getValue()).isEqualTo(1);
viewModel.clearActionLiveData();
assertThat(actionLiveData.getValue()).isNull();
}
@Test
public void testGetEnrollmentRequest() {
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newAllFalseRequest(mApplication));
assertThat(viewModel.getRequest()).isNotNull();
}
@Test
public void testOnStartToUpdateEnrollableStatusOk_isSuw() {
setupFingerprintEnrolledFingerprints(mFingerprintManager, TEST_USER_ID, 0);
setupSuwMaxFingerprintsEnrollable(mApplication, mResources, 1);
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(mApplication));
final FingerprintEnrollIntroStatus status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_OK);
}
@Test
public void testOnStartToUpdateEnrollableStatusReachMax_isSuw() {
setupFingerprintEnrolledFingerprints(mFingerprintManager, TEST_USER_ID, 1);
setupSuwMaxFingerprintsEnrollable(mApplication, mResources, 1);
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(mApplication));
final FingerprintEnrollIntroStatus status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX);
}
@Test
public void testOnStartToUpdateEnrollableStatusOk_isNotSuw() {
testOnStartToUpdateEnrollableStatusOk(newAllFalseRequest(mApplication));
}
@Test
public void testOnStartToUpdateEnrollableStatusReachMax_isNotSuw() {
testOnStartToUpdateEnrollableStatusReachMax(newAllFalseRequest(mApplication));
}
@Test
public void testOnStartToUpdateEnrollableStatusOk_isSuwDeferred() {
testOnStartToUpdateEnrollableStatusOk(newIsSuwDeferredRequest(mApplication));
}
@Test
public void testOnStartToUpdateEnrollableStatusReachMax_isSuwDeferred() {
testOnStartToUpdateEnrollableStatusReachMax(newIsSuwDeferredRequest(mApplication));
}
@Test
public void testOnStartToUpdateEnrollableStatusOk_isSuwPortal() {
testOnStartToUpdateEnrollableStatusOk(newIsSuwPortalRequest(mApplication));
}
@Test
public void testOnStartToUpdateEnrollableStatusReachMax_isSuwPortal() {
testOnStartToUpdateEnrollableStatusReachMax(newIsSuwPortalRequest(mApplication));
}
@Test
public void testOnStartToUpdateEnrollableStatusOk_isSuwSuggestedActionFlow() {
testOnStartToUpdateEnrollableStatusOk(newIsSuwSuggestedActionFlowRequest(mApplication));
}
@Test
public void testOnStartToUpdateEnrollableStatusReachMax_isSuwSuggestedActionFlow() {
testOnStartToUpdateEnrollableStatusReachMax(
newIsSuwSuggestedActionFlowRequest(mApplication));
}
private void testOnStartToUpdateEnrollableStatusOk(@NonNull EnrollmentRequest request) {
setupFingerprintEnrolledFingerprints(mFingerprintManager, TEST_USER_ID, 0);
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5),
request);
FingerprintEnrollIntroStatus status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_OK);
}
private void testOnStartToUpdateEnrollableStatusReachMax(@NonNull EnrollmentRequest request) {
setupFingerprintEnrolledFingerprints(mFingerprintManager, TEST_USER_ID, 5);
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5),
request);
FingerprintEnrollIntroStatus status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX);
}
@Test
public void testIsParentalConsentRequired() {
// We shall not mock FingerprintRepository, but
// FingerprintRepository.isParentalConsentRequired() calls static method inside, we can't
// mock static method
final FingerprintRepository fingerprintRepository = mock(FingerprintRepository.class);
final FingerprintEnrollIntroViewModel viewModel = new FingerprintEnrollIntroViewModel(
mApplication, fingerprintRepository, newAllFalseRequest(mApplication),
TEST_USER_ID);
when(fingerprintRepository.isParentalConsentRequired(mApplication)).thenReturn(true);
assertThat(viewModel.isParentalConsentRequired()).isEqualTo(true);
when(fingerprintRepository.isParentalConsentRequired(mApplication)).thenReturn(false);
assertThat(viewModel.isParentalConsentRequired()).isEqualTo(false);
}
@Test
public void testIsBiometricUnlockDisabledByAdmin() {
// We shall not mock FingerprintRepository, but
// FingerprintRepository.isDisabledByAdmin() calls static method inside, we can't mock
// static method
final FingerprintRepository fingerprintRepository = mock(FingerprintRepository.class);
final FingerprintEnrollIntroViewModel viewModel = new FingerprintEnrollIntroViewModel(
mApplication, fingerprintRepository, newAllFalseRequest(mApplication),
TEST_USER_ID);
when(fingerprintRepository.isDisabledByAdmin(mApplication, TEST_USER_ID)).thenReturn(true);
assertThat(viewModel.isBiometricUnlockDisabledByAdmin()).isEqualTo(true);
when(fingerprintRepository.isDisabledByAdmin(mApplication, TEST_USER_ID)).thenReturn(false);
assertThat(viewModel.isBiometricUnlockDisabledByAdmin()).isEqualTo(false);
}
@Test
public void testSetHasScrolledToBottom() {
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newAllFalseRequest(mApplication));
viewModel.setHasScrolledToBottom(true);
FingerprintEnrollIntroStatus status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.hasScrollToBottom()).isEqualTo(true);
viewModel.setHasScrolledToBottom(false);
status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.hasScrollToBottom()).isEqualTo(false);
}
@Test
public void testOnNextButtonClick_enrollNext() {
// Set latest status to FINGERPRINT_ENROLLABLE_OK
setupFingerprintEnrolledFingerprints(mFingerprintManager, TEST_USER_ID, 0);
setupSuwMaxFingerprintsEnrollable(mApplication, mResources, 1);
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(mApplication));
FingerprintEnrollIntroStatus status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_OK);
// Perform click on `next`
viewModel.onNextButtonClick();
assertThat(viewModel.getActionLiveData().getValue())
.isEqualTo(FINGERPRINT_ENROLL_INTRO_ACTION_CONTINUE_ENROLL);
}
@Test
public void testOnNextButtonClick_doneAndFinish() {
// Set latest status to FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
setupFingerprintEnrolledFingerprints(mFingerprintManager, TEST_USER_ID, 1);
setupSuwMaxFingerprintsEnrollable(mApplication, mResources, 1);
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(mApplication));
FingerprintEnrollIntroStatus status = viewModel.getPageStatusLiveData().getValue();
assertThat(status.getEnrollableStatus()).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX);
// Perform click on `next`
viewModel.onNextButtonClick();
assertThat(viewModel.getActionLiveData().getValue())
.isEqualTo(FINGERPRINT_ENROLL_INTRO_ACTION_DONE_AND_FINISH);
}
@Test
public void testOnSkipOrCancelButtonClick() {
final FingerprintEnrollIntroViewModel viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(mFingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newAllFalseRequest(mApplication));
viewModel.onSkipOrCancelButtonClick();
assertThat(viewModel.getActionLiveData().getValue())
.isEqualTo(FINGERPRINT_ENROLL_INTRO_ACTION_SKIP_OR_CANCEL);
}
}

View File

@@ -0,0 +1,377 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.settings.biometrics2.ui.viewmodel
import android.app.Application
import android.content.res.Resources
import android.hardware.fingerprint.FingerprintManager
import android.hardware.fingerprint.FingerprintSensorProperties.TYPE_UDFPS_OPTICAL
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settings.biometrics2.data.repository.FingerprintRepository
import com.android.settings.biometrics2.ui.model.EnrollmentRequest
import com.android.settings.biometrics2.ui.model.FingerprintEnrollIntroStatus
import com.android.settings.biometrics2.ui.model.FingerprintEnrollable.FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
import com.android.settings.biometrics2.ui.model.FingerprintEnrollable.FINGERPRINT_ENROLLABLE_OK
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroAction.CONTINUE_ENROLL
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroAction.DONE_AND_FINISH
import com.android.settings.biometrics2.ui.viewmodel.FingerprintEnrollIntroAction.SKIP_OR_CANCEL
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newAllFalseRequest
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwDeferredRequest
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwPortalRequest
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwRequest
import com.android.settings.biometrics2.utils.EnrollmentRequestUtils.newIsSuwSuggestedActionFlowRequest
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.newFingerprintRepository
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupFingerprintEnrolledFingerprints
import com.android.settings.biometrics2.utils.FingerprintRepositoryUtils.setupSuwMaxFingerprintsEnrollable
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.toList
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnit
@RunWith(AndroidJUnit4::class)
class FingerprintEnrollIntroViewModelTest {
@get:Rule val mockito = MockitoJUnit.rule()
@Mock private lateinit var resources: Resources
@Mock private lateinit var fingerprintManager: FingerprintManager
private var application: Application = ApplicationProvider.getApplicationContext()
private fun newFingerprintEnrollIntroViewModel(
fingerprintRepository: FingerprintRepository,
enrollmentRequest: EnrollmentRequest
) = FingerprintEnrollIntroViewModel(
application,
fingerprintRepository,
enrollmentRequest,
TEST_USER_ID
)
@Before
fun setUp() {
application = ApplicationProvider.getApplicationContext()
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testPageStatusFlowDefaultAndUpdate() = runTest {
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 1),
newAllFalseRequest(application)
)
val statusList = listOfPageStatusFlow(viewModel)
runCurrent()
// assert default values
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].hasScrollToBottom()).isFalse()
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_OK)
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 1)
viewModel.updateEnrollableStatus(backgroundScope)
runCurrent()
// assert new updated value
assertThat(statusList.size).isEqualTo(2)
assertThat(statusList[1].hasScrollToBottom()).isFalse()
assertThat(statusList[1].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)
}
@OptIn(ExperimentalCoroutinesApi::class)
fun testOnStartToUpdateEnrollableStatusOk_isSuw() = runTest {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 0)
setupSuwMaxFingerprintsEnrollable(application, resources, 1)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(application)
)
val statusList = listOfPageStatusFlow(viewModel)
runCurrent()
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_OK)
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuw() = runTest {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 1)
setupSuwMaxFingerprintsEnrollable(application, resources, 1)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(application)
)
val statusList = listOfPageStatusFlow(viewModel)
runCurrent()
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusOk_isNotSuw() = runTest {
testOnStartToUpdateEnrollableStatusOk(newAllFalseRequest(application))
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isNotSuw() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(newAllFalseRequest(application))
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusOk_isSuwDeferred() = runTest {
testOnStartToUpdateEnrollableStatusOk(newIsSuwDeferredRequest(application))
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuwDeferred() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(newIsSuwDeferredRequest(application))
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusOk_isSuwPortal() = runTest {
testOnStartToUpdateEnrollableStatusOk(newIsSuwPortalRequest(application))
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuwPortal() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(newIsSuwPortalRequest(application))
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusOk_isSuwSuggestedActionFlow() = runTest {
testOnStartToUpdateEnrollableStatusOk(newIsSuwSuggestedActionFlowRequest(application))
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnStartToUpdateEnrollableStatusReachMax_isSuwSuggestedActionFlow() = runTest {
testOnStartToUpdateEnrollableStatusReachMax(
newIsSuwSuggestedActionFlowRequest(application)
)
}
@OptIn(ExperimentalCoroutinesApi::class)
private fun TestScope.testOnStartToUpdateEnrollableStatusOk(request: EnrollmentRequest) {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 0)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
request
)
val statusList = listOfPageStatusFlow(viewModel)
runCurrent()
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_OK)
}
@OptIn(ExperimentalCoroutinesApi::class)
private fun TestScope.testOnStartToUpdateEnrollableStatusReachMax(request: EnrollmentRequest) {
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 5)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
request
)
val statusList = listOfPageStatusFlow(viewModel)
runCurrent()
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)
}
@Test
fun testIsParentalConsentRequired() {
// We shall not mock FingerprintRepository, but
// FingerprintRepository.isParentalConsentRequired() calls static method inside, we can't
// mock static method
val fingerprintRepository = Mockito.mock(
FingerprintRepository::class.java
)
val viewModel = FingerprintEnrollIntroViewModel(
application,
fingerprintRepository,
newAllFalseRequest(application),
TEST_USER_ID
)
Mockito.`when`(
fingerprintRepository.isParentalConsentRequired(application)
).thenReturn(true)
assertThat(viewModel.isParentalConsentRequired).isEqualTo(true)
Mockito.`when`(
fingerprintRepository.isParentalConsentRequired(application)
).thenReturn(false)
assertThat(viewModel.isParentalConsentRequired).isEqualTo(false)
}
@Test
fun testIsBiometricUnlockDisabledByAdmin() {
// We shall not mock FingerprintRepository, but
// FingerprintRepository.isDisabledByAdmin() calls static method inside, we can't mock
// static method
val fingerprintRepository = Mockito.mock(FingerprintRepository::class.java)
val viewModel = FingerprintEnrollIntroViewModel(
application,
fingerprintRepository,
newAllFalseRequest(application),
TEST_USER_ID
)
Mockito.`when`(
fingerprintRepository.isDisabledByAdmin(application, TEST_USER_ID)
).thenReturn(true)
assertThat(viewModel.isBiometricUnlockDisabledByAdmin).isEqualTo(true)
Mockito.`when`(
fingerprintRepository.isDisabledByAdmin(application, TEST_USER_ID)
).thenReturn(false)
assertThat(viewModel.isBiometricUnlockDisabledByAdmin).isEqualTo(false)
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testSetHasScrolledToBottom() = runTest {
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newAllFalseRequest(application)
)
val pageStatusList = listOfPageStatusFlow(viewModel)
viewModel.setHasScrolledToBottom(true, backgroundScope)
runCurrent()
assertThat(pageStatusList[pageStatusList.size-1].hasScrollToBottom()).isEqualTo(true)
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnNextButtonClick_enrollNext() = runTest {
// Set latest status to FINGERPRINT_ENROLLABLE_OK
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 0)
setupSuwMaxFingerprintsEnrollable(application, resources, 1)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(application)
)
val actions = listOfActionFlow(viewModel)
// Perform click on `next`
viewModel.onNextButtonClick(backgroundScope)
runCurrent()
assertThat(actions.size).isEqualTo(1)
assertThat(actions[0]).isEqualTo(CONTINUE_ENROLL)
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnNextButtonClick_doneAndFinish() = runTest {
// Set latest status to FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX
setupFingerprintEnrolledFingerprints(fingerprintManager, TEST_USER_ID, 1)
setupSuwMaxFingerprintsEnrollable(application, resources, 1)
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newIsSuwRequest(application)
)
val statusList = listOfPageStatusFlow(viewModel)
val actionList = listOfActionFlow(viewModel)
runCurrent()
assertThat(statusList.size).isEqualTo(1)
assertThat(statusList[0].enrollableStatus).isEqualTo(FINGERPRINT_ENROLLABLE_ERROR_REACH_MAX)
val actions = listOfActionFlow(viewModel)
// Perform click on `next`
viewModel.onNextButtonClick(backgroundScope)
runCurrent()
assertThat(actionList.size).isEqualTo(1)
assertThat(actionList[0]).isEqualTo(DONE_AND_FINISH)
}
@OptIn(ExperimentalCoroutinesApi::class)
@Test
fun testOnSkipOrCancelButtonClick() = runTest {
val viewModel = newFingerprintEnrollIntroViewModel(
newFingerprintRepository(fingerprintManager, TYPE_UDFPS_OPTICAL, 5),
newAllFalseRequest(application)
)
val actions = listOfActionFlow(viewModel)
viewModel.onSkipOrCancelButtonClick(backgroundScope)
runCurrent()
assertThat(actions.size).isEqualTo(1)
assertThat(actions[0]).isEqualTo(SKIP_OR_CANCEL)
}
@OptIn(ExperimentalCoroutinesApi::class)
private fun TestScope.listOfActionFlow(
viewModel: FingerprintEnrollIntroViewModel
): List<FingerprintEnrollIntroAction> =
mutableListOf<FingerprintEnrollIntroAction>().also {
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.actionFlow.toList(it)
}
}
@OptIn(ExperimentalCoroutinesApi::class)
private fun TestScope.listOfPageStatusFlow(
viewModel: FingerprintEnrollIntroViewModel
): List<FingerprintEnrollIntroStatus> =
mutableListOf<FingerprintEnrollIntroStatus>().also {
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.pageStatusFlow.toList(it)
}
}
companion object {
private const val TEST_USER_ID = 33
}
}