mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 18:56:44 -04:00
Use SuggestionSearch
instead of Search
for better search functionality.
* Since `Search` is not compatible with those zim files which does not have Xapian index but `SuggestionSearch` have this functionality to search inside those zim files so we have used this. * Update test cases for test new search functionality.
This commit is contained in:
parent
6235ba612a
commit
c4dbe478b8
@ -37,9 +37,8 @@ import org.kiwix.libkiwix.JNIKiwixException
|
||||
import org.kiwix.libzim.Archive
|
||||
import org.kiwix.libzim.DirectAccessInfo
|
||||
import org.kiwix.libzim.Item
|
||||
import org.kiwix.libzim.Query
|
||||
import org.kiwix.libzim.Search
|
||||
import org.kiwix.libzim.Searcher
|
||||
import org.kiwix.libzim.SuggestionSearch
|
||||
import org.kiwix.libzim.SuggestionSearcher
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.IOException
|
||||
@ -56,7 +55,7 @@ class ZimFileReader constructor(
|
||||
val zimFile: File,
|
||||
private val jniKiwixReader: Archive,
|
||||
private val nightModeConfig: NightModeConfig,
|
||||
private val searcher: Searcher = Searcher(jniKiwixReader)
|
||||
private val searcher: SuggestionSearcher = SuggestionSearcher(jniKiwixReader)
|
||||
) {
|
||||
interface Factory {
|
||||
fun create(file: File): ZimFileReader?
|
||||
@ -130,9 +129,9 @@ class ZimFileReader constructor(
|
||||
null
|
||||
}
|
||||
|
||||
fun searchSuggestions(prefix: String): Search? =
|
||||
fun searchSuggestions(prefix: String): SuggestionSearch? =
|
||||
try {
|
||||
searcher.search(Query(prefix))
|
||||
searcher.suggest(prefix)
|
||||
} catch (ignore: Exception) {
|
||||
// to handled the exception if there is no FT Xapian index found in the current zim file
|
||||
null
|
||||
|
@ -22,14 +22,14 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.coroutines.yield
|
||||
import org.kiwix.kiwixmobile.core.reader.ZimFileReader
|
||||
import org.kiwix.libzim.Search
|
||||
import org.kiwix.libzim.SuggestionSearch
|
||||
import javax.inject.Inject
|
||||
|
||||
interface SearchResultGenerator {
|
||||
suspend fun generateSearchResults(
|
||||
searchTerm: String,
|
||||
zimFileReader: ZimFileReader?
|
||||
): Search?
|
||||
): SuggestionSearch?
|
||||
}
|
||||
|
||||
class ZimSearchResultGenerator @Inject constructor() : SearchResultGenerator {
|
||||
|
@ -30,7 +30,7 @@ data class SearchState(
|
||||
if (searchTerm.isEmpty()) {
|
||||
recentResults
|
||||
} else {
|
||||
searchResultsWithTerm.search?.let {
|
||||
searchResultsWithTerm.suggestionSearch?.let {
|
||||
val maximumResults = it.estimatedMatches
|
||||
val safeEndIndex =
|
||||
if (startIndex + 100 < maximumResults) startIndex + 100 else maximumResults
|
||||
|
@ -59,7 +59,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
|
||||
import org.kiwix.libzim.SuggestionSearch
|
||||
import javax.inject.Inject
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@ -174,4 +174,4 @@ class SearchViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
data class SearchResultsWithTerm(val searchTerm: String, val search: Search?)
|
||||
data class SearchResultsWithTerm(val searchTerm: String, val suggestionSearch: SuggestionSearch?)
|
||||
|
@ -30,11 +30,11 @@ internal class SearchStateTest {
|
||||
@Test
|
||||
internal fun `visibleResults use searchResults when searchTerm is not empty`() {
|
||||
val searchTerm = "notEmpty"
|
||||
val searchWrapper: SearchWrapper = mockk()
|
||||
val searchIteratorWrapper: SearchIteratorWrapper = mockk()
|
||||
val entryWrapper: EntryWrapper = mockk()
|
||||
val suggestionSearchWrapper: SuggestionSearchWrapper = mockk()
|
||||
val searchIteratorWrapper: SuggestionIteratorWrapper = mockk()
|
||||
val entryWrapper: SuggestionItemWrapper = mockk()
|
||||
val estimatedMatches = 1
|
||||
every { searchWrapper.estimatedMatches } returns estimatedMatches.toLong()
|
||||
every { suggestionSearchWrapper.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.
|
||||
@ -42,7 +42,7 @@ internal class SearchStateTest {
|
||||
every { searchIteratorWrapper.next() } returns entryWrapper
|
||||
every { entryWrapper.title } returns searchTerm
|
||||
every {
|
||||
searchWrapper.getResults(
|
||||
suggestionSearchWrapper.getResults(
|
||||
0,
|
||||
estimatedMatches
|
||||
)
|
||||
@ -50,7 +50,7 @@ internal class SearchStateTest {
|
||||
assertThat(
|
||||
SearchState(
|
||||
searchTerm,
|
||||
SearchResultsWithTerm("", searchWrapper),
|
||||
SearchResultsWithTerm("", suggestionSearchWrapper),
|
||||
emptyList(),
|
||||
FromWebView
|
||||
).getVisibleResults(0)
|
||||
|
@ -74,7 +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
|
||||
import org.kiwix.libzim.SuggestionSearch
|
||||
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
internal class SearchViewModelTest {
|
||||
@ -122,12 +122,12 @@ internal class SearchViewModelTest {
|
||||
val item = ZimSearchResultListItem("")
|
||||
val searchTerm = "searchTerm"
|
||||
val searchOrigin = FromWebView
|
||||
val search: Search = mockk()
|
||||
val suggestionSearch: SuggestionSearch = mockk()
|
||||
viewModel.state.test(this)
|
||||
.also {
|
||||
emissionOf(
|
||||
searchTerm = searchTerm,
|
||||
search = search,
|
||||
suggestionSearch = suggestionSearch,
|
||||
databaseResults = listOf(RecentSearchListItem("")),
|
||||
searchOrigin = searchOrigin
|
||||
)
|
||||
@ -135,7 +135,7 @@ internal class SearchViewModelTest {
|
||||
.assertValue(
|
||||
SearchState(
|
||||
searchTerm,
|
||||
SearchResultsWithTerm(searchTerm, search),
|
||||
SearchResultsWithTerm(searchTerm, suggestionSearch),
|
||||
listOf(RecentSearchListItem("")),
|
||||
searchOrigin
|
||||
)
|
||||
@ -243,14 +243,14 @@ internal class SearchViewModelTest {
|
||||
|
||||
private fun TestScope.emissionOf(
|
||||
searchTerm: String,
|
||||
search: Search,
|
||||
suggestionSearch: SuggestionSearch,
|
||||
databaseResults: List<RecentSearchListItem>,
|
||||
searchOrigin: SearchOrigin
|
||||
) {
|
||||
|
||||
coEvery {
|
||||
searchResultGenerator.generateSearchResults(searchTerm, zimFileReader)
|
||||
} returns search
|
||||
} returns suggestionSearch
|
||||
viewModel.actions.trySend(Filter(searchTerm)).isSuccess
|
||||
recentsFromDb.trySend(databaseResults).isSuccess
|
||||
viewModel.actions.trySend(ScreenWasStartedFrom(searchOrigin)).isSuccess
|
||||
|
@ -18,8 +18,8 @@
|
||||
|
||||
package org.kiwix.kiwixmobile.core.search.viewmodel
|
||||
|
||||
import org.kiwix.libzim.Entry
|
||||
import org.kiwix.libzim.SuggestionItem
|
||||
|
||||
internal class EntryWrapper : Entry() {
|
||||
class SuggestionItemWrapper : SuggestionItem() {
|
||||
override fun getTitle(): String = super.getTitle()
|
||||
}
|
@ -18,12 +18,11 @@
|
||||
|
||||
package org.kiwix.kiwixmobile.core.search.viewmodel
|
||||
|
||||
import org.kiwix.libzim.SearchIterator
|
||||
import org.kiwix.libzim.SuggestionIterator
|
||||
|
||||
// Create this as a helper class, as we can not directly use libkiwix/libzim functions in testing
|
||||
internal class SearchIteratorWrapper : SearchIterator() {
|
||||
class SuggestionIteratorWrapper : SuggestionIterator() {
|
||||
override fun remove() {}
|
||||
|
||||
override fun hasNext(): Boolean = super.hasNext()
|
||||
override fun next(): EntryWrapper = super.next() as EntryWrapper
|
||||
override fun next(): SuggestionItemWrapper = super.next() as SuggestionItemWrapper
|
||||
}
|
@ -18,12 +18,11 @@
|
||||
|
||||
package org.kiwix.kiwixmobile.core.search.viewmodel
|
||||
|
||||
import org.kiwix.libzim.Search
|
||||
import org.kiwix.libzim.SuggestionSearch
|
||||
|
||||
// Create this as a helper class, as we can not directly use libkiwix/libzim functions in testing
|
||||
internal class SearchWrapper : Search() {
|
||||
class SuggestionSearchWrapper : SuggestionSearch() {
|
||||
override fun getEstimatedMatches(): Long = super.getEstimatedMatches()
|
||||
|
||||
override fun getResults(start: Int, maxResults: Int): SearchIteratorWrapper =
|
||||
super.getResults(start, maxResults) as SearchIteratorWrapper
|
||||
override fun getResults(start: Int, maxResults: Int): SuggestionIteratorWrapper =
|
||||
super.getResults(start, maxResults) as SuggestionIteratorWrapper
|
||||
}
|
@ -44,11 +44,11 @@ internal class ZimSearchResultGeneratorTest {
|
||||
@Test
|
||||
internal fun `suggestion results are distinct`() {
|
||||
val searchTerm = " "
|
||||
val searchWrapper: SearchWrapper = mockk()
|
||||
every { zimFileReader.searchSuggestions(searchTerm) } returns searchWrapper
|
||||
val suggestionSearchWrapper: SuggestionSearchWrapper = mockk()
|
||||
every { zimFileReader.searchSuggestions(searchTerm) } returns suggestionSearchWrapper
|
||||
runBlocking {
|
||||
assertThat(zimSearchResultGenerator.generateSearchResults(searchTerm, zimFileReader))
|
||||
.isEqualTo(searchWrapper)
|
||||
.isEqualTo(suggestionSearchWrapper)
|
||||
verify {
|
||||
zimFileReader.searchSuggestions(searchTerm)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user