Updated test cases to accommodate the new search functionality.

* Due to linking errors with libkiwix/libzim functions, direct usage in testing was not possible. To address this, helper classes were created, similar to those in `java-libkiwix`, for testing the search functionality.
This commit is contained in:
MohitMali 2023-08-01 19:48:56 +05:30
parent f03830c62f
commit 90e7e8d7f7
6 changed files with 123 additions and 25 deletions

View File

@ -0,0 +1,25 @@
/*
* Kiwix Android
* Copyright (c) 2023 Kiwix <android.kiwix.org>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.kiwix.kiwixmobile.core.search.viewmodel
import org.kiwix.libzim.Entry
internal class EntryWrapper : Entry() {
override fun getTitle(): String = super.getTitle()
}

View File

@ -0,0 +1,29 @@
/*
* Kiwix Android
* Copyright (c) 2023 Kiwix <android.kiwix.org>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.kiwix.kiwixmobile.core.search.viewmodel
import org.kiwix.libzim.SearchIterator
// Create this as a helper class, as we can not directly use libkiwix/libzim functions in testing
internal class SearchIteratorWrapper : SearchIterator() {
override fun remove() {}
override fun hasNext(): Boolean = super.hasNext()
override fun next(): EntryWrapper = super.next() as EntryWrapper
}

View File

@ -18,25 +18,43 @@
package org.kiwix.kiwixmobile.core.search.viewmodel
import io.mockk.every
import io.mockk.mockk
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.kiwix.kiwixmobile.core.search.adapter.SearchListItem.RecentSearchListItem
import org.kiwix.kiwixmobile.core.search.adapter.SearchListItem.ZimSearchResultListItem
import org.kiwix.kiwixmobile.core.search.viewmodel.SearchOrigin.FromWebView
internal class SearchStateTest {
@Test
internal fun `visibleResults use searchResults when searchTerm is not empty`() {
val results = listOf(ZimSearchResultListItem(""))
val searchTerm = "notEmpty"
val searchWrapper: SearchWrapper = mockk()
val searchIteratorWrapper: SearchIteratorWrapper = mockk()
val entryWrapper: EntryWrapper = mockk()
val estimatedMatches = 1
every { searchWrapper.estimatedMatches } returns estimatedMatches.toLong()
// Settings list to hasNext() to ensure it returns true only for the first call.
// Otherwise, if we do not set this, the method will always return true when checking if the iterator has a next value,
// causing our test case to get stuck in an infinite loop due to this explicit setting.
every { searchIteratorWrapper.hasNext() } returnsMany listOf(true, false)
every { searchIteratorWrapper.next() } returns entryWrapper
every { entryWrapper.title } returns searchTerm
every {
searchWrapper.getResults(
0,
estimatedMatches
)
} returns searchIteratorWrapper
assertThat(
SearchState(
"notEmpty",
SearchResultsWithTerm("", results),
searchTerm,
SearchResultsWithTerm("", searchWrapper),
emptyList(),
FromWebView
).getVisibleResults(0)
).isEqualTo(results)
).isEqualTo(listOf(RecentSearchListItem(searchTerm)))
}
@Test
@ -45,7 +63,7 @@ internal class SearchStateTest {
assertThat(
SearchState(
"",
SearchResultsWithTerm("", emptyList()),
SearchResultsWithTerm("", null),
results,
FromWebView
).getVisibleResults(0)
@ -57,11 +75,11 @@ internal class SearchStateTest {
assertThat(
SearchState(
"",
SearchResultsWithTerm("notEqual", emptyList()),
SearchResultsWithTerm("notEqual", null),
emptyList(),
FromWebView
).isLoading
).isTrue()
).isTrue
}
@Test
@ -70,10 +88,10 @@ internal class SearchStateTest {
assertThat(
SearchState(
searchTerm,
SearchResultsWithTerm(searchTerm, emptyList()),
SearchResultsWithTerm(searchTerm, null),
emptyList(),
FromWebView
).isLoading
).isFalse()
).isFalse
}
}

View File

@ -74,6 +74,7 @@ import org.kiwix.kiwixmobile.core.search.viewmodel.effects.SearchInPreviousScree
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.ShowDeleteSearchDialog
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.ShowToast
import org.kiwix.kiwixmobile.core.search.viewmodel.effects.StartSpeechInput
import org.kiwix.libzim.Search
@OptIn(ExperimentalCoroutinesApi::class)
internal class SearchViewModelTest {
@ -101,7 +102,7 @@ internal class SearchViewModelTest {
every { zimReaderContainer.copyReader() } returns zimFileReader
coEvery {
searchResultGenerator.generateSearchResults("", zimFileReader)
} returns emptyList()
} returns null
every { zimReaderContainer.id } returns "id"
every { recentSearchDao.recentSearches("id") } returns recentsFromDb.consumeAsFlow()
viewModel = SearchViewModel(recentSearchDao, zimReaderContainer, searchResultGenerator)
@ -112,7 +113,7 @@ internal class SearchViewModelTest {
@Test
fun `initial state is Initialising`() = runBlockingTest {
viewModel.state.test(this).assertValue(
SearchState("", SearchResultsWithTerm("", emptyList()), emptyList(), FromWebView)
SearchState("", SearchResultsWithTerm("", null), emptyList(), FromWebView)
).finish()
}
@ -121,11 +122,12 @@ internal class SearchViewModelTest {
val item = ZimSearchResultListItem("")
val searchTerm = "searchTerm"
val searchOrigin = FromWebView
val search: Search = mockk()
viewModel.state.test(this)
.also {
emissionOf(
searchTerm = searchTerm,
searchResults = listOf(item),
search = search,
databaseResults = listOf(RecentSearchListItem("")),
searchOrigin = searchOrigin
)
@ -133,7 +135,7 @@ internal class SearchViewModelTest {
.assertValue(
SearchState(
searchTerm,
SearchResultsWithTerm(searchTerm, listOf(item)),
SearchResultsWithTerm(searchTerm, search),
listOf(RecentSearchListItem("")),
searchOrigin
)
@ -241,14 +243,14 @@ internal class SearchViewModelTest {
private fun TestScope.emissionOf(
searchTerm: String,
searchResults: List<ZimSearchResultListItem>,
search: Search,
databaseResults: List<RecentSearchListItem>,
searchOrigin: SearchOrigin
) {
coEvery {
searchResultGenerator.generateSearchResults(searchTerm, zimFileReader)
} returns searchResults
} returns search
viewModel.actions.trySend(Filter(searchTerm)).isSuccess
recentsFromDb.trySend(databaseResults).isSuccess
viewModel.actions.trySend(ScreenWasStartedFrom(searchOrigin)).isSuccess

View File

@ -0,0 +1,29 @@
/*
* Kiwix Android
* Copyright (c) 2023 Kiwix <android.kiwix.org>
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.kiwix.kiwixmobile.core.search.viewmodel
import org.kiwix.libzim.Search
// Create this as a helper class, as we can not directly use libkiwix/libzim functions in testing
internal class SearchWrapper : Search() {
override fun getEstimatedMatches(): Long = super.getEstimatedMatches()
override fun getResults(start: Int, maxResults: Int): SearchIteratorWrapper =
super.getResults(start, maxResults) as SearchIteratorWrapper
}

View File

@ -25,8 +25,6 @@ import kotlinx.coroutines.runBlocking
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Test
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
import org.kiwix.kiwixmobile.core.search.adapter.SearchListItem.ZimSearchResultListItem
import org.kiwix.libzim.Search
internal class ZimSearchResultGeneratorTest {
@ -39,21 +37,18 @@ internal class ZimSearchResultGeneratorTest {
internal fun `empty search term returns empty list`() {
runBlocking {
assertThat(zimSearchResultGenerator.generateSearchResults("", zimFileReader))
.isEqualTo(emptyList<ZimSearchResultListItem>())
.isEqualTo(null)
}
}
@Test
internal fun `suggestion results are distinct`() {
val validTitle = "title"
val searchTerm = " "
val item = ZimSearchResultListItem(validTitle)
val search: Search = mockk()
every { zimFileReader.searchSuggestions(searchTerm) } returns search
every { zimFileReader.getSearchResultList(search) } returns listOf(item)
val searchWrapper: SearchWrapper = mockk()
every { zimFileReader.searchSuggestions(searchTerm) } returns searchWrapper
runBlocking {
assertThat(zimSearchResultGenerator.generateSearchResults(searchTerm, zimFileReader))
.isEqualTo(listOf(ZimSearchResultListItem(validTitle)))
.isEqualTo(searchWrapper)
verify {
zimFileReader.searchSuggestions(searchTerm)
}