Loading packages/CredentialManager/wear/robotests/Android.bp 0 → 100644 +28 −0 Original line number Original line Diff line number Diff line package { // See: http://go/android-license-faq default_applicable_licenses: ["frameworks_base_license"], } android_robolectric_test { name: "CredentialSelectorTests", srcs: [ "src/**/*.kt", ], // Include test libraries. instrumentation_for: "ClockworkCredentialManager", libs: [ "androidx.test.runner", "androidx.test.ext.junit", "kotlinx_coroutines_android", "kotlinx_coroutines", "kotlinx-coroutines-core", "kotlinx_coroutines_test", "mockito-robolectric-prebuilt", "mockito-kotlin2", "CredentialManagerShared", "ClockworkCredentialManager", "framework_graphics_flags_java_lib", ], java_resource_dirs: ["config"], upstream: true, } packages/CredentialManager/wear/robotests/config/robolectric.properties 0 → 100644 +16 −0 Original line number Original line Diff line number Diff line # Copyright (C) 2024 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. # sdk=NEWEST_SDK packages/CredentialManager/wear/robotests/src/com/android/credentialmanager/CredentialSelectorViewModelTest.kt 0 → 100644 +241 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2024 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.credentialmanager import org.mockito.kotlin.whenever import com.android.credentialmanager.model.EntryInfo import com.android.credentialmanager.model.Request import androidx.test.filters.SmallTest import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Test import org.junit.Before import java.util.Collections.emptyList import org.junit.runner.RunWith import android.content.Intent import com.android.credentialmanager.client.CredentialManagerClient import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import android.credentials.selection.BaseDialogResult import com.google.common.truth.Truth.assertThat import org.mockito.kotlin.doReturn import kotlinx.coroutines.Job import org.junit.After import org.robolectric.shadows.ShadowLooper import org.mockito.kotlin.mock import org.mockito.kotlin.verify import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.ExperimentalCoroutinesApi /** Unit tests for [CredentialSelectorViewModel]. */ @ExperimentalCoroutinesApi @SmallTest @RunWith(AndroidJUnit4::class) class CredentialSelectorViewModelTest { private val testScope = TestScope(UnconfinedTestDispatcher()) private val stateFlow: MutableStateFlow<Request?> = MutableStateFlow(Request.Create(null)) private val credentialManagerClient = mock<CredentialManagerClient>{ on { requests } doReturn stateFlow } private val mViewModel = CredentialSelectorViewModel(credentialManagerClient) private lateinit var job: Job val testEntryInfo = EntryInfo( providerId = "", entryKey = "", entrySubkey = "", pendingIntent = null, fillInIntent = null, shouldTerminateUiUponSuccessfulProviderResult = true) @Before fun setUp() { job = checkNotNull(mViewModel).uiState.launchIn(testScope) } @After fun teardown() { job.cancel() } @Test fun `Setting state to idle when receiving null request`() { stateFlow.value = null ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Idle) } @Test fun `Setting state to cancel when receiving Cancel request`() { stateFlow.value = Request.Cancel(appName = "appName", token = null) ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value) .isEqualTo(CredentialSelectorUiState.Cancel("appName")) } @Test fun `Setting state to create when receiving Create request`() { stateFlow.value = Request.Create(token = null) ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Create) } @Test fun `Closing app when receiving Close request`() { stateFlow.value = Request.Close(token = null) ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Updates request`() { val intent = Intent() mViewModel.updateRequest(intent) verify(credentialManagerClient).updateRequest(intent) } @Test fun `Back on a single entry screen closes app`() { mViewModel.openSecondaryScreen() stateFlow.value = Request.Get( token = null, resultReceiver = null, finalResponseReceiver = null, providerInfos = emptyList()) mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Back on a multiple entry screen gets us back to a primary screen`() { mViewModel.openSecondaryScreen() stateFlow.value = Request.Get( token = null, resultReceiver = null, finalResponseReceiver = null, providerInfos = emptyList()) mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Back on create request state closes app`() { stateFlow.value = Request.Create(token = null) mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Back on close request state closes app`() { stateFlow.value = Request.Close(token = null) mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Back on cancel request state closes app`() { stateFlow.value = Request.Cancel(appName = "", token = null) mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Back on idle request state closes app`() { stateFlow.value = null mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Cancel closes the app`() { mViewModel.cancel() ShadowLooper.idleMainLooper() verify(credentialManagerClient).sendError(BaseDialogResult.RESULT_CODE_DIALOG_USER_CANCELED) assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Send entry selection result closes app and calls client method`() { whenever(credentialManagerClient.sendEntrySelectionResult( entryInfo = testEntryInfo, resultCode = null, resultData = null, isAutoSelected = false )).thenReturn(true) mViewModel.sendSelectionResult( entryInfo = testEntryInfo, resultCode = null, resultData = null, isAutoSelected = false) ShadowLooper.idleMainLooper() verify(credentialManagerClient).sendEntrySelectionResult( testEntryInfo, null, null, false ) assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Send entry selection result does not close app on false return`() { whenever(credentialManagerClient.sendEntrySelectionResult( entryInfo = testEntryInfo, resultCode = null, resultData = null, isAutoSelected = false )).thenReturn(false) stateFlow.value = Request.Create(null) mViewModel.sendSelectionResult(entryInfo = testEntryInfo, resultCode = null, resultData = null, isAutoSelected = false) ShadowLooper.idleMainLooper() verify(credentialManagerClient).sendEntrySelectionResult( entryInfo = testEntryInfo, resultCode = null, resultData = null, isAutoSelected = false ) assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Create) } } packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +3 −1 Original line number Original line Diff line number Diff line Loading @@ -59,8 +59,10 @@ class CredentialSelectorViewModel @Inject constructor( isPrimaryScreen, isPrimaryScreen, shouldClose shouldClose ) { request, isPrimary, shouldClose -> ) { request, isPrimary, shouldClose -> Log.d(TAG, "Request updated: " + request?.toString() + " isClose: " + shouldClose.toString() + " isPrimaryScreen: " + isPrimary.toString()) if (shouldClose) { if (shouldClose) { Log.d(TAG, "Request finished, closing ") return@combine Close return@combine Close } } Loading Loading
packages/CredentialManager/wear/robotests/Android.bp 0 → 100644 +28 −0 Original line number Original line Diff line number Diff line package { // See: http://go/android-license-faq default_applicable_licenses: ["frameworks_base_license"], } android_robolectric_test { name: "CredentialSelectorTests", srcs: [ "src/**/*.kt", ], // Include test libraries. instrumentation_for: "ClockworkCredentialManager", libs: [ "androidx.test.runner", "androidx.test.ext.junit", "kotlinx_coroutines_android", "kotlinx_coroutines", "kotlinx-coroutines-core", "kotlinx_coroutines_test", "mockito-robolectric-prebuilt", "mockito-kotlin2", "CredentialManagerShared", "ClockworkCredentialManager", "framework_graphics_flags_java_lib", ], java_resource_dirs: ["config"], upstream: true, }
packages/CredentialManager/wear/robotests/config/robolectric.properties 0 → 100644 +16 −0 Original line number Original line Diff line number Diff line # Copyright (C) 2024 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. # sdk=NEWEST_SDK
packages/CredentialManager/wear/robotests/src/com/android/credentialmanager/CredentialSelectorViewModelTest.kt 0 → 100644 +241 −0 Original line number Original line Diff line number Diff line /* * Copyright (C) 2024 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.credentialmanager import org.mockito.kotlin.whenever import com.android.credentialmanager.model.EntryInfo import com.android.credentialmanager.model.Request import androidx.test.filters.SmallTest import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Test import org.junit.Before import java.util.Collections.emptyList import org.junit.runner.RunWith import android.content.Intent import com.android.credentialmanager.client.CredentialManagerClient import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.launchIn import android.credentials.selection.BaseDialogResult import com.google.common.truth.Truth.assertThat import org.mockito.kotlin.doReturn import kotlinx.coroutines.Job import org.junit.After import org.robolectric.shadows.ShadowLooper import org.mockito.kotlin.mock import org.mockito.kotlin.verify import kotlinx.coroutines.test.UnconfinedTestDispatcher import kotlinx.coroutines.test.TestScope import kotlinx.coroutines.ExperimentalCoroutinesApi /** Unit tests for [CredentialSelectorViewModel]. */ @ExperimentalCoroutinesApi @SmallTest @RunWith(AndroidJUnit4::class) class CredentialSelectorViewModelTest { private val testScope = TestScope(UnconfinedTestDispatcher()) private val stateFlow: MutableStateFlow<Request?> = MutableStateFlow(Request.Create(null)) private val credentialManagerClient = mock<CredentialManagerClient>{ on { requests } doReturn stateFlow } private val mViewModel = CredentialSelectorViewModel(credentialManagerClient) private lateinit var job: Job val testEntryInfo = EntryInfo( providerId = "", entryKey = "", entrySubkey = "", pendingIntent = null, fillInIntent = null, shouldTerminateUiUponSuccessfulProviderResult = true) @Before fun setUp() { job = checkNotNull(mViewModel).uiState.launchIn(testScope) } @After fun teardown() { job.cancel() } @Test fun `Setting state to idle when receiving null request`() { stateFlow.value = null ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Idle) } @Test fun `Setting state to cancel when receiving Cancel request`() { stateFlow.value = Request.Cancel(appName = "appName", token = null) ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value) .isEqualTo(CredentialSelectorUiState.Cancel("appName")) } @Test fun `Setting state to create when receiving Create request`() { stateFlow.value = Request.Create(token = null) ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Create) } @Test fun `Closing app when receiving Close request`() { stateFlow.value = Request.Close(token = null) ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Updates request`() { val intent = Intent() mViewModel.updateRequest(intent) verify(credentialManagerClient).updateRequest(intent) } @Test fun `Back on a single entry screen closes app`() { mViewModel.openSecondaryScreen() stateFlow.value = Request.Get( token = null, resultReceiver = null, finalResponseReceiver = null, providerInfos = emptyList()) mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Back on a multiple entry screen gets us back to a primary screen`() { mViewModel.openSecondaryScreen() stateFlow.value = Request.Get( token = null, resultReceiver = null, finalResponseReceiver = null, providerInfos = emptyList()) mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Back on create request state closes app`() { stateFlow.value = Request.Create(token = null) mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Back on close request state closes app`() { stateFlow.value = Request.Close(token = null) mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Back on cancel request state closes app`() { stateFlow.value = Request.Cancel(appName = "", token = null) mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Back on idle request state closes app`() { stateFlow.value = null mViewModel.back() ShadowLooper.idleMainLooper() assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Cancel closes the app`() { mViewModel.cancel() ShadowLooper.idleMainLooper() verify(credentialManagerClient).sendError(BaseDialogResult.RESULT_CODE_DIALOG_USER_CANCELED) assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Send entry selection result closes app and calls client method`() { whenever(credentialManagerClient.sendEntrySelectionResult( entryInfo = testEntryInfo, resultCode = null, resultData = null, isAutoSelected = false )).thenReturn(true) mViewModel.sendSelectionResult( entryInfo = testEntryInfo, resultCode = null, resultData = null, isAutoSelected = false) ShadowLooper.idleMainLooper() verify(credentialManagerClient).sendEntrySelectionResult( testEntryInfo, null, null, false ) assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Close) } @Test fun `Send entry selection result does not close app on false return`() { whenever(credentialManagerClient.sendEntrySelectionResult( entryInfo = testEntryInfo, resultCode = null, resultData = null, isAutoSelected = false )).thenReturn(false) stateFlow.value = Request.Create(null) mViewModel.sendSelectionResult(entryInfo = testEntryInfo, resultCode = null, resultData = null, isAutoSelected = false) ShadowLooper.idleMainLooper() verify(credentialManagerClient).sendEntrySelectionResult( entryInfo = testEntryInfo, resultCode = null, resultData = null, isAutoSelected = false ) assertThat(mViewModel.uiState.value).isEqualTo(CredentialSelectorUiState.Create) } }
packages/CredentialManager/wear/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +3 −1 Original line number Original line Diff line number Diff line Loading @@ -59,8 +59,10 @@ class CredentialSelectorViewModel @Inject constructor( isPrimaryScreen, isPrimaryScreen, shouldClose shouldClose ) { request, isPrimary, shouldClose -> ) { request, isPrimary, shouldClose -> Log.d(TAG, "Request updated: " + request?.toString() + " isClose: " + shouldClose.toString() + " isPrimaryScreen: " + isPrimary.toString()) if (shouldClose) { if (shouldClose) { Log.d(TAG, "Request finished, closing ") return@combine Close return@combine Close } } Loading