Files
Lawnchair/tests/multivalentTests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
T
Sunny Goyal 42975c39db Making various model objects injectable
Bug: 361850561
Test: Updated tests
Flag: EXEMPT dagger
Change-Id: Ibb45b72c186e6aeeed7a37b0ae3f8083472019d7
2025-03-10 14:37:43 -07:00

212 lines
7.6 KiB
Kotlin

/*
* Copyright (C) 2022 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.model
import android.util.Pair
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.util.Executors
import com.android.launcher3.util.IntArray
import com.android.launcher3.util.TestUtil.runOnExecutorSync
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito.times
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
/** Tests for [AddWorkspaceItemsTask] */
@SmallTest
@RunWith(AndroidJUnit4::class)
class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
private lateinit var mDataModelCallbacks: MyCallbacks
private val mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder = mock()
@Before
override fun setup() {
super.setup()
mDataModelCallbacks = MyCallbacks()
Executors.MAIN_EXECUTOR.submit { mModelHelper.model.addCallbacks(mDataModelCallbacks) }
.get()
}
@After
override fun tearDown() {
super.tearDown()
}
@Test
fun givenNewItemAndNonEmptyPages_whenExecuteTask_thenAddNewItem() {
val itemToAdd = getNewItem()
val nonEmptyScreenIds = listOf(0, 1, 2)
givenNewItemSpaces(NewItemSpace(1, 2, 2))
val addedItems = testAddItems(nonEmptyScreenIds, itemToAdd)
assertThat(addedItems.size).isEqualTo(1)
assertThat(addedItems.first().itemInfo.screenId).isEqualTo(1)
assertThat(addedItems.first().isAnimated).isTrue()
verifyItemSpaceFinderCall(nonEmptyScreenIds, numberOfExpectedCall = 1)
}
@Test
fun givenNewAndExistingItems_whenExecuteTask_thenOnlyAddNewItem() {
val itemsToAdd = arrayOf(getNewItem(), getExistingItem())
givenNewItemSpaces(NewItemSpace(1, 0, 0))
val nonEmptyScreenIds = listOf(0)
val addedItems = testAddItems(nonEmptyScreenIds, *itemsToAdd)
assertThat(addedItems.size).isEqualTo(1)
assertThat(addedItems.first().itemInfo.screenId).isEqualTo(1)
assertThat(addedItems.first().isAnimated).isTrue()
verifyItemSpaceFinderCall(nonEmptyScreenIds, numberOfExpectedCall = 1)
}
@Test
fun givenOnlyExistingItem_whenExecuteTask_thenDoNotAddItem() {
val itemToAdd = getExistingItem()
givenNewItemSpaces(NewItemSpace(1, 0, 0))
val nonEmptyScreenIds = listOf(0)
val addedItems = testAddItems(nonEmptyScreenIds, itemToAdd)
assertThat(addedItems.size).isEqualTo(0)
// b/343530737
verifyNoMoreInteractions(mWorkspaceItemSpaceFinder)
}
@Test
fun givenNonSequentialScreenIds_whenExecuteTask_thenReturnNewScreenId() {
val itemToAdd = getNewItem()
givenNewItemSpaces(NewItemSpace(2, 1, 3))
val nonEmptyScreenIds = listOf(0, 2, 3)
val addedItems = testAddItems(nonEmptyScreenIds, itemToAdd)
assertThat(addedItems.size).isEqualTo(1)
assertThat(addedItems.first().itemInfo.screenId).isEqualTo(2)
assertThat(addedItems.first().isAnimated).isTrue()
verifyItemSpaceFinderCall(nonEmptyScreenIds, numberOfExpectedCall = 1)
}
@Test
fun givenMultipleItems_whenExecuteTask_thenAddThem() {
val itemsToAdd =
arrayOf(getNewItem(), getExistingItem(), getNewItem(), getNewItem(), getExistingItem())
givenNewItemSpaces(NewItemSpace(1, 3, 3), NewItemSpace(2, 0, 0), NewItemSpace(2, 0, 1))
val nonEmptyScreenIds = listOf(0, 1)
val addedItems = testAddItems(nonEmptyScreenIds, *itemsToAdd)
// Only the new items should be added
assertThat(addedItems.size).isEqualTo(3)
// Items that are added to the first screen should not be animated
val itemsAddedToFirstScreen = addedItems.filter { it.itemInfo.screenId == 1 }
assertThat(itemsAddedToFirstScreen.size).isEqualTo(1)
assertThat(itemsAddedToFirstScreen.first().isAnimated).isFalse()
// Items that are added to the second screen should be animated
val itemsAddedToSecondScreen = addedItems.filter { it.itemInfo.screenId == 2 }
assertThat(itemsAddedToSecondScreen.size).isEqualTo(2)
itemsAddedToSecondScreen.forEach { assertThat(it.isAnimated).isTrue() }
verifyItemSpaceFinderCall(nonEmptyScreenIds, numberOfExpectedCall = 3)
}
/** Sets up the item space data that will be returned from WorkspaceItemSpaceFinder. */
private fun givenNewItemSpaces(vararg newItemSpaces: NewItemSpace) {
val spaceStack = newItemSpaces.toMutableList()
whenever(mWorkspaceItemSpaceFinder.findSpaceForItem(any(), any(), any(), any())).then {
spaceStack.removeFirst().toIntArray()
}
}
/**
* Verifies if WorkspaceItemSpaceFinder was called with proper arguments and how many times was
* it called.
*/
private fun verifyItemSpaceFinderCall(nonEmptyScreenIds: List<Int>, numberOfExpectedCall: Int) {
verify(mWorkspaceItemSpaceFinder, times(numberOfExpectedCall))
.findSpaceForItem(
eq(IntArray.wrap(*nonEmptyScreenIds.toIntArray())),
eq(IntArray()),
eq(1),
eq(1),
)
}
/**
* Sets up the workspaces with items, executes the task, collects the added items from the model
* callback then returns it.
*/
private fun testAddItems(
nonEmptyScreenIds: List<Int>,
vararg itemsToAdd: WorkspaceItemInfo,
): List<AddedItem> {
setupWorkspaces(nonEmptyScreenIds)
val task = newTask(*itemsToAdd)
val addedItems = mutableListOf<AddedItem>()
runOnExecutorSync(Executors.MODEL_EXECUTOR) {
mDataModelCallbacks.addedItems.clear()
mModelHelper.model.enqueueModelUpdateTask(task)
runOnExecutorSync(Executors.MAIN_EXECUTOR) {}
addedItems.addAll(mDataModelCallbacks.addedItems)
}
return addedItems
}
/**
* Creates the task with the given items and replaces the WorkspaceItemSpaceFinder dependency
* with a mock.
*/
private fun newTask(vararg items: ItemInfo): AddWorkspaceItemsTask =
items
.map { Pair.create(it, Any()) }
.toMutableList()
.let { AddWorkspaceItemsTask(it, mWorkspaceItemSpaceFinder) }
}
private data class AddedItem(val itemInfo: ItemInfo, val isAnimated: Boolean)
private class MyCallbacks : BgDataModel.Callbacks {
val addedItems = mutableListOf<AddedItem>()
override fun bindAppsAdded(
newScreens: IntArray?,
addNotAnimated: ArrayList<ItemInfo>,
addAnimated: ArrayList<ItemInfo>,
) {
addedItems.addAll(addAnimated.map { AddedItem(it, true) })
addedItems.addAll(addNotAnimated.map { AddedItem(it, false) })
}
}