Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2019 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package androidx.biometric; |
| 18 | |
| 19 | import static com.google.common.truth.Truth.assertThat; |
| 20 | |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 21 | import static org.mockito.ArgumentMatchers.any; |
| 22 | import static org.mockito.ArgumentMatchers.anyLong; |
Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 23 | import static org.mockito.Mockito.verify; |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 24 | import static org.mockito.Mockito.when; |
| 25 | |
| 26 | import android.os.Build; |
| 27 | import android.os.Handler; |
Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 28 | |
Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 29 | import androidx.annotation.NonNull; |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 30 | import androidx.test.filters.LargeTest; |
Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 31 | |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 32 | import org.junit.Before; |
Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 33 | import org.junit.Test; |
| 34 | import org.junit.runner.RunWith; |
| 35 | import org.mockito.ArgumentCaptor; |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 36 | import org.mockito.Captor; |
| 37 | import org.mockito.Mock; |
| 38 | import org.mockito.MockitoAnnotations; |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 39 | import org.mockito.invocation.InvocationOnMock; |
| 40 | import org.mockito.stubbing.Answer; |
Curtis Belmonte | 53dc66f | 2019-11-06 13:17:04 -0800 | [diff] [blame] | 41 | import org.robolectric.RobolectricTestRunner; |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 42 | import org.robolectric.annotation.Config; |
Curtis Belmonte | 53dc66f | 2019-11-06 13:17:04 -0800 | [diff] [blame] | 43 | import org.robolectric.annotation.internal.DoNotInstrument; |
Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 44 | |
| 45 | import java.util.concurrent.Executor; |
| 46 | |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 47 | @LargeTest |
Curtis Belmonte | 53dc66f | 2019-11-06 13:17:04 -0800 | [diff] [blame] | 48 | @RunWith(RobolectricTestRunner.class) |
| 49 | @DoNotInstrument |
Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 50 | public class BiometricFragmentTest { |
Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 51 | private static final Executor EXECUTOR = new Executor() { |
| 52 | @Override |
| 53 | public void execute(@NonNull Runnable runnable) { |
| 54 | runnable.run(); |
| 55 | } |
| 56 | }; |
| 57 | |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 58 | @Mock private BiometricPrompt.AuthenticationCallback mAuthenticationCallback; |
| 59 | @Mock private Handler mHandler; |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 60 | |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 61 | @Captor private ArgumentCaptor<BiometricPrompt.AuthenticationResult> mResultCaptor; |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 62 | |
| 63 | private BiometricFragment mFragment; |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 64 | private BiometricViewModel mViewModel; |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 65 | |
| 66 | @Before |
| 67 | public void setUp() { |
| 68 | MockitoAnnotations.initMocks(this); |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 69 | prepareMockHandler(mHandler); |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 70 | mFragment = BiometricFragment.newInstance(); |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 71 | mViewModel = new BiometricViewModel(); |
| 72 | mFragment.mHandler = mHandler; |
| 73 | mFragment.mViewModel = mViewModel; |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 74 | } |
| 75 | |
Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 76 | @Test |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 77 | public void testCancel_DoesNotCrash_WhenNotAssociatedWithFragmentManager() { |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 78 | mFragment.cancelAuthentication(BiometricFragment.CANCELED_FROM_NONE); |
Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 79 | } |
Curtis Belmonte | 0b2dee8 | 2019-11-06 10:00:17 -0800 | [diff] [blame] | 80 | |
| 81 | @Test |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 82 | public void testOnAuthenticationSucceeded_TriggersCallbackWithNullCrypto_WhenGivenNullResult() { |
| 83 | mViewModel.setClientExecutor(EXECUTOR); |
| 84 | mViewModel.setClientCallback(mAuthenticationCallback); |
| 85 | mViewModel.setAwaitingResult(true); |
| 86 | |
Curtis Belmonte | bc1f6af | 2020-07-08 11:43:22 -0700 | [diff] [blame^] | 87 | mFragment.onAuthenticationSucceeded( |
| 88 | new BiometricPrompt.AuthenticationResult( |
| 89 | null /* crypto */, BiometricPrompt.AUTHENTICATION_RESULT_TYPE_BIOMETRIC)); |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 90 | |
| 91 | verify(mAuthenticationCallback).onAuthenticationSucceeded(mResultCaptor.capture()); |
| 92 | assertThat(mResultCaptor.getValue().getCryptoObject()).isNull(); |
| 93 | } |
| 94 | |
| 95 | @Test |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 96 | @Config(minSdk = Build.VERSION_CODES.M, maxSdk = Build.VERSION_CODES.O_MR1) |
| 97 | public void testOnFingerprintError_DoesShowErrorAndDismiss_WhenHardwareUnavailable() { |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 98 | final int errMsgId = BiometricConstants.ERROR_HW_UNAVAILABLE; |
| 99 | final String errString = "lorem ipsum"; |
Curtis Belmonte | 69dec4a | 2020-05-28 17:14:04 -0700 | [diff] [blame] | 100 | |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 101 | mViewModel.setClientExecutor(EXECUTOR); |
| 102 | mViewModel.setClientCallback(mAuthenticationCallback); |
| 103 | mViewModel.setPromptShowing(true); |
| 104 | mViewModel.setAwaitingResult(true); |
| 105 | mViewModel.setFingerprintDialogDismissedInstantly(false); |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 106 | |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 107 | mFragment.onAuthenticationError(errMsgId, errString); |
| 108 | |
| 109 | assertThat(mViewModel.getFingerprintDialogState().getValue()) |
| 110 | .isEqualTo(FingerprintDialogFragment.STATE_FINGERPRINT_ERROR); |
| 111 | assertThat(mViewModel.getFingerprintDialogHelpMessage().getValue()).isEqualTo(errString); |
| 112 | assertThat(mViewModel.isPromptShowing()).isFalse(); |
Curtis Belmonte | 39817ae | 2020-05-01 15:25:35 -0700 | [diff] [blame] | 113 | verify(mAuthenticationCallback).onAuthenticationError(errMsgId, errString); |
Curtis Belmonte | 0b2dee8 | 2019-11-06 10:00:17 -0800 | [diff] [blame] | 114 | } |
Curtis Belmonte | a4e238a | 2020-06-08 10:58:06 -0700 | [diff] [blame] | 115 | |
| 116 | @Test |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 117 | public void testAuthenticate_ReturnsWithoutError_WhenDetached() { |
| 118 | mFragment.authenticate( |
| 119 | new BiometricPrompt.PromptInfo.Builder() |
| 120 | .setTitle("Title") |
| 121 | .setNegativeButtonText("Cancel") |
| 122 | .build(), |
| 123 | null /* crypto */); |
Curtis Belmonte | a4e238a | 2020-06-08 10:58:06 -0700 | [diff] [blame] | 124 | } |
| 125 | |
Curtis Belmonte | ac3c818 | 2020-06-08 10:48:12 -0700 | [diff] [blame] | 126 | private static void prepareMockHandler(Handler mockHandler) { |
| 127 | // Immediately invoke any scheduled callbacks. |
| 128 | when(mockHandler.postDelayed(any(Runnable.class), anyLong())) |
| 129 | .thenAnswer(new Answer<Boolean>() { |
| 130 | @Override |
| 131 | public Boolean answer(InvocationOnMock invocation) { |
| 132 | final Runnable runnable = invocation.getArgument(0); |
| 133 | if (runnable != null) { |
| 134 | runnable.run(); |
| 135 | } |
| 136 | return true; |
| 137 | } |
| 138 | }); |
Curtis Belmonte | a4e238a | 2020-06-08 10:58:06 -0700 | [diff] [blame] | 139 | } |
Curtis Belmonte | d02b8af | 2019-09-11 14:33:54 -0700 | [diff] [blame] | 140 | } |