From b1db1cf9767a9a5851fac97ffcaefafbf22067ef Mon Sep 17 00:00:00 2001 From: Kainalu Hagiwara Date: Wed, 5 Aug 2020 10:00:54 -0700 Subject: [PATCH] Add tests for Bookmarks DiffUtil and ViewHolders. --- .../library/bookmarks/BookmarkAdapter.kt | 4 +- .../viewholders/BookmarkItemViewHolder.kt | 4 +- .../library/bookmarks/BookmarkAdapterTest.kt | 62 +++++++- .../BookmarkFolderViewHolderTest.kt | 91 +++++++++++ .../viewholders/BookmarkItemViewHolderTest.kt | 147 ++++++++++++++++++ 5 files changed, 305 insertions(+), 3 deletions(-) create mode 100644 app/src/test/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkFolderViewHolderTest.kt create mode 100644 app/src/test/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkItemViewHolderTest.kt diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapter.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapter.kt index ffcea7455..e191bffa3 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapter.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapter.kt @@ -7,6 +7,7 @@ package org.mozilla.fenix.library.bookmarks import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.annotation.VisibleForTesting import androidx.core.view.isVisible import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView @@ -49,7 +50,8 @@ class BookmarkAdapter(val emptyView: View, val interactor: BookmarkViewInteracto diffUtil.dispatchUpdatesTo(this) } - private class BookmarkDiffUtil( + @VisibleForTesting + internal class BookmarkDiffUtil( val old: List, val new: List, val oldMode: BookmarkFragmentState.Mode, diff --git a/app/src/main/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkItemViewHolder.kt b/app/src/main/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkItemViewHolder.kt index 840b716ef..b97fe86c7 100644 --- a/app/src/main/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkItemViewHolder.kt +++ b/app/src/main/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkItemViewHolder.kt @@ -4,6 +4,7 @@ package org.mozilla.fenix.library.bookmarks.viewholders +import androidx.annotation.VisibleForTesting import mozilla.components.concept.storage.BookmarkNode import org.mozilla.fenix.ext.hideAndDisable import org.mozilla.fenix.ext.showAndEnable @@ -66,7 +67,8 @@ class BookmarkItemViewHolder( setSelectionListeners(item, selectionHolder) } - private fun setColorsAndIcons(url: String?) { + @VisibleForTesting + internal fun setColorsAndIcons(url: String?) { if (url != null && url.startsWith("http")) { containerView.loadFavicon(url) } else { diff --git a/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapterTest.kt b/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapterTest.kt index 12ae932ed..b80e584a7 100644 --- a/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapterTest.kt +++ b/app/src/test/java/org/mozilla/fenix/library/bookmarks/BookmarkAdapterTest.kt @@ -9,6 +9,8 @@ import io.mockk.spyk import io.mockk.verifyOrder import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNodeType +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -19,6 +21,16 @@ internal class BookmarkAdapterTest { private lateinit var bookmarkAdapter: BookmarkAdapter + private val item = BookmarkNode( + BookmarkNodeType.ITEM, + "456", + "123", + 0, + "Mozilla", + "http://mozilla.org", + null + ) + @Before fun setup() { bookmarkAdapter = spyk( @@ -30,7 +42,7 @@ internal class BookmarkAdapterTest { fun `update adapter from tree of bookmark nodes, null tree returns empty list`() { val tree = BookmarkNode( BookmarkNodeType.FOLDER, "123", null, 0, "Mobile", null, listOf( - BookmarkNode(BookmarkNodeType.ITEM, "456", "123", 0, "Mozilla", "http://mozilla.org", null), + item, BookmarkNode(BookmarkNodeType.SEPARATOR, "789", "123", 1, null, null, null), BookmarkNode( BookmarkNodeType.ITEM, @@ -52,4 +64,52 @@ internal class BookmarkAdapterTest { bookmarkAdapter.notifyItemRangeRemoved(0, 3) } } + + @Test + fun `items are the same if they have the same guids`() { + assertTrue(createSingleItemDiffUtil(item, item).areItemsTheSame(0, 0)) + assertTrue( + createSingleItemDiffUtil( + item, + item.copy(title = "Wikipedia.org", url = "https://www.wikipedia.org") + ).areItemsTheSame(0, 0) + ) + assertFalse( + createSingleItemDiffUtil( + item, + item.copy(guid = "111") + ).areItemsTheSame(0, 0) + ) + } + + @Test + fun `equal items have same contents unless their selected state changes`() { + assertTrue(createSingleItemDiffUtil(item, item).areContentsTheSame(0, 0)) + assertFalse( + createSingleItemDiffUtil(item, item.copy(position = 1)).areContentsTheSame(0, 0) + ) + assertFalse( + createSingleItemDiffUtil( + item, + item, + oldMode = BookmarkFragmentState.Mode.Selecting(setOf(item)) + ).areContentsTheSame(0, 0) + ) + assertFalse( + createSingleItemDiffUtil( + item, + item, + newMode = BookmarkFragmentState.Mode.Selecting(setOf(item)) + ).areContentsTheSame(0, 0) + ) + } + + private fun createSingleItemDiffUtil( + oldItem: BookmarkNode, + newItem: BookmarkNode, + oldMode: BookmarkFragmentState.Mode = BookmarkFragmentState.Mode.Normal(), + newMode: BookmarkFragmentState.Mode = BookmarkFragmentState.Mode.Normal() + ): BookmarkAdapter.BookmarkDiffUtil { + return BookmarkAdapter.BookmarkDiffUtil(listOf(oldItem), listOf(newItem), oldMode, newMode) + } } diff --git a/app/src/test/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkFolderViewHolderTest.kt b/app/src/test/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkFolderViewHolderTest.kt new file mode 100644 index 000000000..e622dbf20 --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkFolderViewHolderTest.kt @@ -0,0 +1,91 @@ +/* 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.library.bookmarks.viewholders + +import androidx.appcompat.content.res.AppCompatResources +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.verify +import mozilla.components.concept.storage.BookmarkNode +import mozilla.components.concept.storage.BookmarkNodeType +import org.junit.Before +import org.junit.Test +import org.mozilla.fenix.ext.hideAndDisable +import org.mozilla.fenix.ext.showAndEnable +import org.mozilla.fenix.library.LibrarySiteItemView +import org.mozilla.fenix.library.SelectionHolder +import org.mozilla.fenix.library.bookmarks.BookmarkFragmentInteractor +import org.mozilla.fenix.library.bookmarks.BookmarkFragmentState +import org.mozilla.fenix.library.bookmarks.BookmarkPayload + +class BookmarkFolderViewHolderTest { + + @MockK + private lateinit var interactor: BookmarkFragmentInteractor + @MockK(relaxed = true) + private lateinit var siteItemView: LibrarySiteItemView + @MockK(relaxed = true) + private lateinit var selectionHolder: SelectionHolder + private lateinit var holder: BookmarkFolderViewHolder + + private val folder = BookmarkNode( + type = BookmarkNodeType.FOLDER, + guid = "456", + parentGuid = "123", + position = 0, + title = "Folder", + url = null, + children = listOf() + ) + + @Before + fun setup() { + MockKAnnotations.init(this) + + mockkStatic(AppCompatResources::class) + every { AppCompatResources.getDrawable(any(), any()) } returns mockk(relaxed = true) + + holder = BookmarkFolderViewHolder(siteItemView, interactor, selectionHolder) + } + + @Test + fun `binds title and selected state`() { + holder.bind(folder, BookmarkFragmentState.Mode.Normal()) + + verify { + siteItemView.titleView.text = folder.title + siteItemView.overflowView.showAndEnable() + siteItemView.changeSelected(false) + } + + every { selectionHolder.selectedItems } returns setOf(folder) + holder.bind(folder, BookmarkFragmentState.Mode.Selecting(setOf(folder))) + + verify { + siteItemView.titleView.text = folder.title + siteItemView.overflowView.hideAndDisable() + siteItemView.changeSelected(true) + } + } + + @Test + fun `bind with payload of no changes does not rebind views`() { + holder.bind( + folder, + BookmarkFragmentState.Mode.Normal(), + BookmarkPayload(false, false, false, false) + ) + + verify(inverse = true) { + siteItemView.titleView.text = folder.title + siteItemView.overflowView.showAndEnable() + siteItemView.overflowView.hideAndDisable() + siteItemView.changeSelected(any()) + } + } +} diff --git a/app/src/test/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkItemViewHolderTest.kt b/app/src/test/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkItemViewHolderTest.kt new file mode 100644 index 000000000..36d64172b --- /dev/null +++ b/app/src/test/java/org/mozilla/fenix/library/bookmarks/viewholders/BookmarkItemViewHolderTest.kt @@ -0,0 +1,147 @@ +/* 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.library.bookmarks.viewholders + +import io.mockk.MockKAnnotations +import io.mockk.every +import io.mockk.impl.annotations.MockK +import io.mockk.verify +import mozilla.components.concept.storage.BookmarkNode +import mozilla.components.concept.storage.BookmarkNodeType +import org.junit.Before +import org.junit.Test +import org.mozilla.fenix.ext.hideAndDisable +import org.mozilla.fenix.ext.showAndEnable +import org.mozilla.fenix.library.LibrarySiteItemView +import org.mozilla.fenix.library.SelectionHolder +import org.mozilla.fenix.library.bookmarks.BookmarkFragmentInteractor +import org.mozilla.fenix.library.bookmarks.BookmarkFragmentState +import org.mozilla.fenix.library.bookmarks.BookmarkPayload + +class BookmarkItemViewHolderTest { + + @MockK + private lateinit var interactor: BookmarkFragmentInteractor + + @MockK(relaxed = true) + private lateinit var siteItemView: LibrarySiteItemView + + @MockK(relaxed = true) + private lateinit var selectionHolder: SelectionHolder + private lateinit var holder: BookmarkItemViewHolder + + private val item = BookmarkNode( + type = BookmarkNodeType.ITEM, + guid = "456", + parentGuid = "123", + position = 0, + title = "Mozilla", + url = "https://www.mozilla.org", + children = listOf() + ) + + @Before + fun setup() { + MockKAnnotations.init(this) + holder = BookmarkItemViewHolder(siteItemView, interactor, selectionHolder) + } + + @Test + fun `binds views for unselected item`() { + holder.bind(item, BookmarkFragmentState.Mode.Normal()) + + verify { + siteItemView.setSelectionInteractor(item, selectionHolder, interactor) + siteItemView.titleView.text = item.title + siteItemView.urlView.text = item.url + siteItemView.overflowView.showAndEnable() + siteItemView.changeSelected(false) + holder.setColorsAndIcons(item.url) + } + } + + @Test + fun `binds views for selected item`() { + every { selectionHolder.selectedItems } returns setOf(item) + holder.bind(item, BookmarkFragmentState.Mode.Selecting(setOf(item))) + + verify { + siteItemView.setSelectionInteractor(item, selectionHolder, interactor) + siteItemView.titleView.text = item.title + siteItemView.urlView.text = item.url + siteItemView.overflowView.hideAndDisable() + siteItemView.changeSelected(true) + holder.setColorsAndIcons(item.url) + } + } + + @Test + fun `bind with payload of no changes does not rebind views`() { + holder.bind( + item, + BookmarkFragmentState.Mode.Normal(), + BookmarkPayload(false, false, false, false) + ) + + verify(inverse = true) { + siteItemView.titleView.text = item.title + siteItemView.urlView.text = item.url + siteItemView.overflowView.showAndEnable() + siteItemView.overflowView.hideAndDisable() + siteItemView.changeSelected(any()) + holder.setColorsAndIcons(item.url) + } + } + + @Test + fun `binding an item with a null title uses the url as the title`() { + val item = item.copy(title = null) + holder.bind(item, BookmarkFragmentState.Mode.Normal()) + + verify { siteItemView.titleView.text = item.url } + } + + @Test + fun `binding an item with a blank title uses the url as the title`() { + val item = item.copy(title = " ") + holder.bind(item, BookmarkFragmentState.Mode.Normal()) + + verify { siteItemView.titleView.text = item.url } + } + + @Test + fun `rebinds title if item title is null and the item url has changed`() { + val item = item.copy(title = null) + holder.bind( + item, + BookmarkFragmentState.Mode.Normal(), + BookmarkPayload( + titleChanged = false, + urlChanged = true, + selectedChanged = false, + modeChanged = false + ) + ) + + verify { siteItemView.titleView.text = item.url } + } + + @Test + fun `rebinds title if item title is blank and the item url has changed`() { + val item = item.copy(title = " ") + holder.bind( + item, + BookmarkFragmentState.Mode.Normal(), + BookmarkPayload( + titleChanged = false, + urlChanged = true, + selectedChanged = false, + modeChanged = false + ) + ) + + verify { siteItemView.titleView.text = item.url } + } +}