From 71a48d9ac538cf9054af9baa2db9d136a467dc44 Mon Sep 17 00:00:00 2001 From: Sihua Ma Date: Wed, 17 Jul 2024 22:01:57 +0000 Subject: [PATCH] Add unit test for CustomWidgetManager Number of methods covered: 5 Test: atest NexusLauncherRoboTests:CustomWidgetManagerTest Test: SysUI studio Flag: TEST_ONLY Bug: 353303621 Change-Id: I69c9567391d3a874c7b2abcd473887194ec2dcfc --- .../widget/custom/CustomWidgetManager.java | 17 ++- .../widget/custom/CustomWidgetManagerTest.kt | 144 ++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 tests/multivalentTests/src/com/android/launcher3/widget/custom/CustomWidgetManagerTest.kt diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java index 50012b36f6..faa5d12875 100644 --- a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java +++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java @@ -30,6 +30,7 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import com.android.launcher3.R; import com.android.launcher3.util.MainThreadInitializedObject; @@ -45,6 +46,7 @@ import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.stream.Stream; @@ -62,9 +64,16 @@ public class CustomWidgetManager implements PluginListener, private final HashMap mPlugins; private final List mCustomWidgets; private Consumer mWidgetRefreshCallback; + private final @NonNull AppWidgetManager mAppWidgetManager; private CustomWidgetManager(Context context) { + this(context, AppWidgetManager.getInstance(context)); + } + + @VisibleForTesting + CustomWidgetManager(Context context, @NonNull AppWidgetManager widgetManager) { mContext = context; + mAppWidgetManager = widgetManager; mPlugins = new HashMap<>(); mCustomWidgets = new ArrayList<>(); PluginManagerWrapper.INSTANCE.get(context) @@ -94,7 +103,7 @@ public class CustomWidgetManager implements PluginListener, @Override public void onPluginConnected(CustomWidgetPlugin plugin, Context context) { - List providers = AppWidgetManager.getInstance(context) + List providers = mAppWidgetManager .getInstalledProvidersForProfile(Process.myUserHandle()); if (providers.isEmpty()) return; Parcel parcel = Parcel.obtain(); @@ -113,6 +122,12 @@ public class CustomWidgetManager implements PluginListener, mCustomWidgets.removeIf(w -> w.getComponent().equals(cn)); } + @VisibleForTesting + @NonNull + Map getPlugins() { + return mPlugins; + } + /** * Inject a callback function to refresh the widgets. */ diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/custom/CustomWidgetManagerTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/custom/CustomWidgetManagerTest.kt new file mode 100644 index 0000000000..4b5710d5ac --- /dev/null +++ b/tests/multivalentTests/src/com/android/launcher3/widget/custom/CustomWidgetManagerTest.kt @@ -0,0 +1,144 @@ +/* + * 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.launcher3.widget.custom + +import android.appwidget.AppWidgetManager +import android.content.ComponentName +import android.os.Process +import android.platform.test.flag.junit.SetFlagsRule +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation +import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext +import com.android.launcher3.util.PluginManagerWrapper +import com.android.launcher3.util.WidgetUtils +import com.android.launcher3.widget.LauncherAppWidgetHostView +import com.android.launcher3.widget.LauncherAppWidgetProviderInfo +import com.android.systemui.plugins.CustomWidgetPlugin +import org.junit.After +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +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.mock +import org.mockito.MockitoAnnotations +import org.mockito.kotlin.any +import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq +import org.mockito.kotlin.same +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +class CustomWidgetManagerTest { + + @get:Rule val setFlagsRule = SetFlagsRule() + + private val context = SandboxModelContext() + private lateinit var underTest: CustomWidgetManager + + @Mock private lateinit var pluginManager: PluginManagerWrapper + @Mock private lateinit var mockAppWidgetManager: AppWidgetManager + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + context.putObject(PluginManagerWrapper.INSTANCE, pluginManager) + underTest = CustomWidgetManager(context, mockAppWidgetManager) + } + + @After + fun tearDown() { + underTest.close() + } + + @Test + fun plugin_manager_added_after_initialization() { + verify(pluginManager) + .addPluginListener(same(underTest), same(CustomWidgetPlugin::class.java), eq(true)) + } + + @Test + fun close_widget_manager_should_remove_plugin_listener() { + underTest.close() + verify(pluginManager).removePluginListener(same(underTest)) + } + + @Test + fun on_plugin_connected_no_provider_info() { + doReturn(emptyList()) + .whenever(mockAppWidgetManager) + .getInstalledProvidersForProfile(any()) + val mockPlugin = mock(CustomWidgetPlugin::class.java) + underTest.onPluginConnected(mockPlugin, context) + assertEquals(0, underTest.plugins.size) + } + + @Test + fun on_plugin_connected_exist_provider_info() { + doReturn(listOf(WidgetUtils.createAppWidgetProviderInfo(TEST_COMPONENT_NAME))) + .whenever(mockAppWidgetManager) + .getInstalledProvidersForProfile(eq(Process.myUserHandle())) + val mockPlugin = mock(CustomWidgetPlugin::class.java) + underTest.onPluginConnected(mockPlugin, context) + assertEquals(1, underTest.plugins.size) + } + + @Test + fun on_plugin_disconnected() { + doReturn(listOf(WidgetUtils.createAppWidgetProviderInfo(TEST_COMPONENT_NAME))) + .whenever(mockAppWidgetManager) + .getInstalledProvidersForProfile(eq(Process.myUserHandle())) + val mockPlugin = mock(CustomWidgetPlugin::class.java) + underTest.onPluginConnected(mockPlugin, context) + underTest.onPluginDisconnected(mockPlugin) + assertEquals(0, underTest.plugins.size) + } + + @Test + fun on_view_created() { + val mockPlugin = mock(CustomWidgetPlugin::class.java) + val mockWidgetView = mock(LauncherAppWidgetHostView::class.java) + val mockProviderInfo = mock(CustomAppWidgetProviderInfo::class.java) + doReturn(mockProviderInfo).whenever(mockWidgetView).appWidgetInfo + mockProviderInfo.provider = TEST_COMPONENT_NAME + underTest.plugins.put(TEST_COMPONENT_NAME, mockPlugin) + underTest.onViewCreated(mockWidgetView) + verify(mockPlugin).onViewCreated(eq(mockWidgetView)) + } + + @Test + fun generate_stream() { + assertTrue(underTest.stream().toList().isEmpty()) + doReturn(listOf(WidgetUtils.createAppWidgetProviderInfo(TEST_COMPONENT_NAME))) + .whenever(mockAppWidgetManager) + .getInstalledProvidersForProfile(eq(Process.myUserHandle())) + val mockPlugin = mock(CustomWidgetPlugin::class.java) + underTest.onPluginConnected(mockPlugin, context) + assertEquals(1, underTest.stream().toList().size) + } + + companion object { + private const val TEST_CLASS = "TEST_CLASS" + private val TEST_COMPONENT_NAME = + ComponentName(getInstrumentation().targetContext.packageName, TEST_CLASS) + } +}