[fenix] Add tests for adapters in collections (https://github.com/mozilla-mobile/fenix/pull/12649)
parent
f443ca3be0
commit
ded7cde177
@ -0,0 +1,63 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.collections
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import org.mozilla.fenix.home.Tab
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Diff callback for comparing tab lists with selected state.
|
||||||
|
*/
|
||||||
|
internal class TabDiffUtil(
|
||||||
|
private val old: List<Tab>,
|
||||||
|
private val new: List<Tab>,
|
||||||
|
private val oldSelected: Set<Tab>,
|
||||||
|
private val newSelected: Set<Tab>,
|
||||||
|
private val oldHideCheckboxes: Boolean,
|
||||||
|
private val newHideCheckboxes: Boolean
|
||||||
|
) : DiffUtil.Callback() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the tabs in the given positions refer to the same tab (based on ID).
|
||||||
|
*/
|
||||||
|
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
|
||||||
|
old[oldItemPosition].sessionId == new[newItemPosition].sessionId
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the combination of tab ID, selection, and checkbox visibility is the same.
|
||||||
|
*/
|
||||||
|
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
|
||||||
|
val isSameTab = old[oldItemPosition].sessionId == new[newItemPosition].sessionId
|
||||||
|
val sameSelectedState = oldItemSelected(oldItemPosition) == newItemSelected(newItemPosition)
|
||||||
|
val isSameHideCheckboxes = oldHideCheckboxes == newHideCheckboxes
|
||||||
|
return isSameTab && sameSelectedState && isSameHideCheckboxes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a change payload indication if the item is now/no longer selected.
|
||||||
|
*/
|
||||||
|
override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? {
|
||||||
|
val shouldBeChecked = newItemSelected(newItemPosition) && !oldItemSelected(oldItemPosition)
|
||||||
|
val shouldBeUnchecked = !newItemSelected(newItemPosition) && oldItemSelected(oldItemPosition)
|
||||||
|
return CheckChanged(shouldBeChecked, shouldBeUnchecked, newHideCheckboxes)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getOldListSize(): Int = old.size
|
||||||
|
override fun getNewListSize(): Int = new.size
|
||||||
|
|
||||||
|
private fun oldItemSelected(oldItemPosition: Int) = oldSelected.contains(old[oldItemPosition])
|
||||||
|
private fun newItemSelected(newItemPosition: Int) = newSelected.contains(new[newItemPosition])
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property shouldBeChecked Item was previously unchecked and should be checked.
|
||||||
|
* @property shouldBeUnchecked Item was previously checked and should be unchecked.
|
||||||
|
* @property shouldHideCheckBox Checkbox should be visible.
|
||||||
|
*/
|
||||||
|
data class CheckChanged(
|
||||||
|
val shouldBeChecked: Boolean,
|
||||||
|
val shouldBeUnchecked: Boolean,
|
||||||
|
val shouldHideCheckBox: Boolean
|
||||||
|
)
|
@ -0,0 +1,89 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.collections
|
||||||
|
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.core.view.isInvisible
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import kotlinx.android.synthetic.main.collection_tab_list_row.*
|
||||||
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
|
import org.mozilla.fenix.home.Tab
|
||||||
|
|
||||||
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
|
class CollectionCreationTabListAdapterTest {
|
||||||
|
|
||||||
|
private lateinit var interactor: CollectionCreationInteractor
|
||||||
|
private lateinit var adapter: CollectionCreationTabListAdapter
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
interactor = mockk()
|
||||||
|
adapter = CollectionCreationTabListAdapter(interactor)
|
||||||
|
|
||||||
|
every { interactor.selectCollection(any(), any()) } just Runs
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `getItemCount should return the number of tab collections`() {
|
||||||
|
val tab = mockk<Tab>()
|
||||||
|
|
||||||
|
assertEquals(0, adapter.itemCount)
|
||||||
|
|
||||||
|
adapter.updateData(
|
||||||
|
tabs = listOf(tab),
|
||||||
|
selectedTabs = emptySet()
|
||||||
|
)
|
||||||
|
assertEquals(1, adapter.itemCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `creates and binds viewholder`() {
|
||||||
|
val tab = mockk<Tab> {
|
||||||
|
every { sessionId } returns "abc"
|
||||||
|
every { title } returns "Mozilla"
|
||||||
|
every { hostname } returns "mozilla.org"
|
||||||
|
every { url } returns "https://mozilla.org"
|
||||||
|
}
|
||||||
|
adapter.updateData(
|
||||||
|
tabs = listOf(tab),
|
||||||
|
selectedTabs = emptySet()
|
||||||
|
)
|
||||||
|
|
||||||
|
val holder = adapter.createViewHolder(FrameLayout(testContext), 0)
|
||||||
|
adapter.bindViewHolder(holder, 0)
|
||||||
|
|
||||||
|
assertEquals("Mozilla", holder.tab_title.text)
|
||||||
|
assertEquals("mozilla.org", holder.hostname.text)
|
||||||
|
assertFalse(holder.tab_selected_checkbox.isInvisible)
|
||||||
|
assertTrue(holder.itemView.isClickable)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `updateData inserts item`() {
|
||||||
|
val tab = mockk<Tab> {
|
||||||
|
every { sessionId } returns "abc"
|
||||||
|
}
|
||||||
|
val observer = mockk<RecyclerView.AdapterDataObserver>(relaxed = true)
|
||||||
|
adapter.registerAdapterDataObserver(observer)
|
||||||
|
adapter.updateData(
|
||||||
|
tabs = listOf(tab),
|
||||||
|
selectedTabs = emptySet()
|
||||||
|
)
|
||||||
|
|
||||||
|
verify { observer.onItemRangeInserted(0, 1) }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,80 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.collections
|
||||||
|
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import io.mockk.Runs
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
|
import io.mockk.mockk
|
||||||
|
import io.mockk.verify
|
||||||
|
import kotlinx.android.synthetic.main.collections_list_item.view.*
|
||||||
|
import mozilla.components.feature.tab.collections.TabCollection
|
||||||
|
import mozilla.components.support.test.robolectric.testContext
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
|
||||||
|
|
||||||
|
@RunWith(FenixRobolectricTestRunner::class)
|
||||||
|
class SaveCollectionListAdapterTest {
|
||||||
|
|
||||||
|
private lateinit var parent: ViewGroup
|
||||||
|
private lateinit var interactor: CollectionCreationInteractor
|
||||||
|
private lateinit var adapter: SaveCollectionListAdapter
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
parent = FrameLayout(testContext)
|
||||||
|
interactor = mockk()
|
||||||
|
adapter = SaveCollectionListAdapter(interactor)
|
||||||
|
|
||||||
|
every { interactor.selectCollection(any(), any()) } just Runs
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `getItemCount should return the number of tab collections`() {
|
||||||
|
val collection = mockk<TabCollection>()
|
||||||
|
|
||||||
|
assertEquals(0, adapter.itemCount)
|
||||||
|
|
||||||
|
adapter.updateData(
|
||||||
|
tabCollections = listOf(collection),
|
||||||
|
selectedTabs = emptySet()
|
||||||
|
)
|
||||||
|
assertEquals(1, adapter.itemCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `creates and binds viewholder`() {
|
||||||
|
val collection = mockk<TabCollection> {
|
||||||
|
every { id } returns 0L
|
||||||
|
every { title } returns "Collection"
|
||||||
|
every { tabs } returns listOf(
|
||||||
|
mockk {
|
||||||
|
every { url } returns "https://mozilla.org"
|
||||||
|
},
|
||||||
|
mockk {
|
||||||
|
every { url } returns "https://firefox.com"
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
adapter.updateData(
|
||||||
|
tabCollections = listOf(collection),
|
||||||
|
selectedTabs = emptySet()
|
||||||
|
)
|
||||||
|
|
||||||
|
val holder = adapter.createViewHolder(parent, 0)
|
||||||
|
adapter.bindViewHolder(holder, 0)
|
||||||
|
|
||||||
|
assertEquals("Collection", holder.itemView.collection_item.text)
|
||||||
|
assertEquals("mozilla.org, firefox.com", holder.itemView.collection_description.text)
|
||||||
|
|
||||||
|
holder.itemView.performClick()
|
||||||
|
verify { interactor.selectCollection(collection, emptyList()) }
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,151 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.collections
|
||||||
|
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertFalse
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Test
|
||||||
|
import org.mozilla.fenix.home.Tab
|
||||||
|
|
||||||
|
class TabDiffUtilTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `list size is returned`() {
|
||||||
|
val diffUtil = TabDiffUtil(
|
||||||
|
old = listOf(mockk(), mockk()),
|
||||||
|
new = listOf(mockk()),
|
||||||
|
oldSelected = emptySet(),
|
||||||
|
newSelected = emptySet(),
|
||||||
|
oldHideCheckboxes = false,
|
||||||
|
newHideCheckboxes = false
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(2, diffUtil.oldListSize)
|
||||||
|
assertEquals(1, diffUtil.newListSize)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `single lists are the same`() {
|
||||||
|
val tab = mockk<Tab> {
|
||||||
|
every { sessionId } returns "abc"
|
||||||
|
}
|
||||||
|
val diffUtil = TabDiffUtil(
|
||||||
|
old = listOf(tab),
|
||||||
|
new = listOf(tab),
|
||||||
|
oldSelected = emptySet(),
|
||||||
|
newSelected = emptySet(),
|
||||||
|
oldHideCheckboxes = false,
|
||||||
|
newHideCheckboxes = false
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(diffUtil.areItemsTheSame(0, 0))
|
||||||
|
assertTrue(diffUtil.areContentsTheSame(0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `selection affects contents`() {
|
||||||
|
val tab = mockk<Tab> {
|
||||||
|
every { sessionId } returns "abc"
|
||||||
|
}
|
||||||
|
val diffUtil = TabDiffUtil(
|
||||||
|
old = listOf(tab),
|
||||||
|
new = listOf(tab),
|
||||||
|
oldSelected = emptySet(),
|
||||||
|
newSelected = setOf(tab),
|
||||||
|
oldHideCheckboxes = false,
|
||||||
|
newHideCheckboxes = false
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(diffUtil.areItemsTheSame(0, 0))
|
||||||
|
assertFalse(diffUtil.areContentsTheSame(0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `hide checkboxes affects contents`() {
|
||||||
|
val tab = mockk<Tab> {
|
||||||
|
every { sessionId } returns "abc"
|
||||||
|
}
|
||||||
|
val diffUtil = TabDiffUtil(
|
||||||
|
old = listOf(tab),
|
||||||
|
new = listOf(tab),
|
||||||
|
oldSelected = setOf(tab),
|
||||||
|
newSelected = setOf(tab),
|
||||||
|
oldHideCheckboxes = false,
|
||||||
|
newHideCheckboxes = true
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(diffUtil.areItemsTheSame(0, 0))
|
||||||
|
assertFalse(diffUtil.areContentsTheSame(0, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `change payload covers no change case`() {
|
||||||
|
val tab = mockk<Tab>()
|
||||||
|
val payload = TabDiffUtil(
|
||||||
|
old = listOf(tab),
|
||||||
|
new = listOf(tab),
|
||||||
|
oldSelected = setOf(tab),
|
||||||
|
newSelected = setOf(tab),
|
||||||
|
oldHideCheckboxes = false,
|
||||||
|
newHideCheckboxes = false
|
||||||
|
).getChangePayload(0, 0)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CheckChanged(
|
||||||
|
shouldBeChecked = false,
|
||||||
|
shouldBeUnchecked = false,
|
||||||
|
shouldHideCheckBox = false
|
||||||
|
),
|
||||||
|
payload
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `include shouldBeChecked in change payload`() {
|
||||||
|
val tab = mockk<Tab>()
|
||||||
|
val payload = TabDiffUtil(
|
||||||
|
old = listOf(tab),
|
||||||
|
new = listOf(tab),
|
||||||
|
oldSelected = emptySet(),
|
||||||
|
newSelected = setOf(tab),
|
||||||
|
oldHideCheckboxes = false,
|
||||||
|
newHideCheckboxes = false
|
||||||
|
).getChangePayload(0, 0)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CheckChanged(
|
||||||
|
shouldBeChecked = true,
|
||||||
|
shouldBeUnchecked = false,
|
||||||
|
shouldHideCheckBox = false
|
||||||
|
),
|
||||||
|
payload
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `include shouldBeUnchecked in change payload`() {
|
||||||
|
val tab = mockk<Tab>()
|
||||||
|
val payload = TabDiffUtil(
|
||||||
|
old = listOf(tab),
|
||||||
|
new = listOf(tab),
|
||||||
|
oldSelected = setOf(tab),
|
||||||
|
newSelected = emptySet(),
|
||||||
|
oldHideCheckboxes = false,
|
||||||
|
newHideCheckboxes = true
|
||||||
|
).getChangePayload(0, 0)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
CheckChanged(
|
||||||
|
shouldBeChecked = false,
|
||||||
|
shouldBeUnchecked = true,
|
||||||
|
shouldHideCheckBox = true
|
||||||
|
),
|
||||||
|
payload
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue