Fixed: ZimManageViewModelTest which was failing on CI.

This commit is contained in:
MohitMaliFtechiz 2025-06-12 14:53:37 +05:30
parent c2d35e17d4
commit e24d214553
2 changed files with 61 additions and 56 deletions

View File

@ -44,7 +44,6 @@ import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain import kotlinx.coroutines.test.setMain
import kotlinx.coroutines.withTimeout
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
@ -95,6 +94,9 @@ import org.kiwix.sharedFunctions.downloadModel
import org.kiwix.sharedFunctions.language import org.kiwix.sharedFunctions.language
import org.kiwix.sharedFunctions.libkiwixBook import org.kiwix.sharedFunctions.libkiwixBook
import java.util.Locale import java.util.Locale
import kotlin.time.Duration
import kotlin.time.DurationUnit
import kotlin.time.toDuration
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
@ExtendWith(InstantExecutorExtension::class) @ExtendWith(InstantExecutorExtension::class)
@ -252,7 +254,7 @@ class ZimManageViewModelTest {
) )
) )
advanceUntilIdle() advanceUntilIdle()
coVerify(timeout = 500) { coVerify(timeout = MOCKK_TIMEOUT_FOR_VERIFICATION) {
libkiwixBookOnDisk.insert(listOfNotNull(expectedBook.book.nativeBook)) libkiwixBookOnDisk.insert(listOfNotNull(expectedBook.book.nativeBook))
} }
} }
@ -359,7 +361,7 @@ class ZimManageViewModelTest {
language(isActive = true, occurencesOfLanguage = 1) language(isActive = true, occurencesOfLanguage = 1)
) )
advanceUntilIdle() advanceUntilIdle()
verify(timeout = 500) { verify(timeout = MOCKK_TIMEOUT_FOR_VERIFICATION) {
newLanguagesDao.insert( newLanguagesDao.insert(
listOf( listOf(
dbLanguage.copy(occurencesOfLanguage = 2), dbLanguage.copy(occurencesOfLanguage = 2),
@ -403,7 +405,9 @@ class ZimManageViewModelTest {
@Test @Test
fun `library update removes from sources and maps to list items`() = runTest { fun `library update removes from sources and maps to list items`() = runTest {
val bookAlreadyOnDisk = libkiwixBook(id = "0", url = "", language = Locale.ENGLISH.language) val book = BookTestWrapper("0")
val bookAlreadyOnDisk =
libkiwixBook(id = "0", url = "", language = Locale.ENGLISH.language, nativeBook = book)
val bookDownloading = libkiwixBook(id = "1", url = "") val bookDownloading = libkiwixBook(id = "1", url = "")
val bookWithActiveLanguage = libkiwixBook(id = "3", language = "activeLanguage", url = "") val bookWithActiveLanguage = libkiwixBook(id = "3", language = "activeLanguage", url = "")
val bookWithInactiveLanguage = libkiwixBook(id = "4", language = "inactiveLanguage", url = "") val bookWithInactiveLanguage = libkiwixBook(id = "4", language = "inactiveLanguage", url = "")
@ -412,42 +416,47 @@ class ZimManageViewModelTest {
triggerAction = { triggerAction = {
every { application.getString(any()) } returns "" every { application.getString(any()) } returns ""
every { application.getString(any(), any()) } returns "" every { application.getString(any(), any()) } returns ""
networkStates.tryEmit(CONNECTED) networkStates.value = CONNECTED
advanceUntilIdle() downloads.value = listOf(downloadModel(book = bookDownloading))
downloads.tryEmit(listOf(downloadModel(book = bookDownloading))) books.value = listOf(bookOnDisk(book = bookAlreadyOnDisk))
advanceUntilIdle() languages.value =
books.tryEmit(listOf(bookOnDisk(book = bookAlreadyOnDisk)))
advanceUntilIdle()
languages.tryEmit(
listOf( listOf(
language(isActive = true, occurencesOfLanguage = 1, languageCode = "activeLanguage"), language(isActive = true, occurencesOfLanguage = 1, languageCode = "activeLanguage"),
language(isActive = false, occurencesOfLanguage = 1, languageCode = "inactiveLanguage") language(isActive = false, occurencesOfLanguage = 1, languageCode = "inactiveLanguage")
) )
) fileSystemStates.value = CanWrite4GbFile
fileSystemStates.tryEmit(CanWrite4GbFile) runBlocking {
advanceUntilIdle() viewModel.networkLibrary.emit(
viewModel.networkLibrary.emit( listOf(
listOf( bookAlreadyOnDisk,
bookAlreadyOnDisk, bookDownloading,
bookDownloading, bookWithActiveLanguage,
bookWithActiveLanguage, bookWithInactiveLanguage
bookWithInactiveLanguage )
) )
) }
advanceUntilIdle()
}, },
assert = { assert = {
skipItems(1) while (true) {
assertThat(awaitItem()).isEqualTo( val items = awaitItem()
listOf( val bookItems = items.filterIsInstance<LibraryListItem.BookItem>()
LibraryListItem.DividerItem(Long.MAX_VALUE, R.string.downloading), if (bookItems.size >= 2 && bookItems[0].fileSystemState == CanWrite4GbFile) {
LibraryListItem.LibraryDownloadItem(downloadModel(book = bookDownloading)), assertThat(items).isEqualTo(
LibraryListItem.DividerItem(Long.MAX_VALUE - 1, R.string.your_languages), listOf(
LibraryListItem.BookItem(bookWithActiveLanguage, CanWrite4GbFile), LibraryListItem.DividerItem(Long.MAX_VALUE, R.string.downloading),
LibraryListItem.DividerItem(Long.MIN_VALUE, R.string.other_languages), LibraryListItem.LibraryDownloadItem(downloadModel(book = bookDownloading)),
LibraryListItem.BookItem(bookWithInactiveLanguage, CanWrite4GbFile) LibraryListItem.DividerItem(Long.MAX_VALUE - 1, R.string.your_languages),
) LibraryListItem.BookItem(bookWithActiveLanguage, CanWrite4GbFile),
) LibraryListItem.DividerItem(Long.MIN_VALUE, R.string.other_languages),
} LibraryListItem.BookItem(bookWithInactiveLanguage, CanWrite4GbFile)
)
)
break
}
}
},
timeout = TURBINE_TIMEOUT
) )
} }
@ -476,22 +485,21 @@ class ZimManageViewModelTest {
viewModel.networkLibrary.emit(listOf(bookOver4Gb)) viewModel.networkLibrary.emit(listOf(bookOver4Gb))
}, },
assert = { assert = {
withTimeout(5000) { while (true) {
while (true) { val item = awaitItem()
val item = awaitItem() val bookItem = item.filterIsInstance<LibraryListItem.BookItem>().firstOrNull()
val bookItem = item.filterIsInstance<LibraryListItem.BookItem>().firstOrNull() if (bookItem?.fileSystemState == CannotWrite4GbFile) {
if (bookItem?.fileSystemState == CannotWrite4GbFile) { assertThat(item).isEqualTo(
assertThat(item).isEqualTo( listOf(
listOf( LibraryListItem.DividerItem(Long.MIN_VALUE, R.string.other_languages),
LibraryListItem.DividerItem(Long.MIN_VALUE, R.string.other_languages), LibraryListItem.BookItem(bookOver4Gb, CannotWrite4GbFile)
LibraryListItem.BookItem(bookOver4Gb, CannotWrite4GbFile)
)
) )
break )
} break
} }
} }
} },
timeout = TURBINE_TIMEOUT
) )
} }
@ -608,10 +616,11 @@ class ZimManageViewModelTest {
suspend fun <T> TestScope.testFlow( suspend fun <T> TestScope.testFlow(
flow: Flow<T>, flow: Flow<T>,
triggerAction: suspend () -> Unit, triggerAction: suspend () -> Unit,
assert: suspend TurbineTestContext<T>.() -> Unit assert: suspend TurbineTestContext<T>.() -> Unit,
timeout: Duration? = null
) { ) {
val job = launch { val job = launch {
flow.test { flow.test(timeout = timeout) {
triggerAction() triggerAction()
assert() assert()
cancelAndIgnoreRemainingEvents() cancelAndIgnoreRemainingEvents()
@ -625,3 +634,6 @@ class BookTestWrapper(private val id: String) : Book(0L) {
override fun equals(other: Any?): Boolean = other is BookTestWrapper && getId() == other.getId() override fun equals(other: Any?): Boolean = other is BookTestWrapper && getId() == other.getId()
override fun hashCode(): Int = getId().hashCode() override fun hashCode(): Int = getId().hashCode()
} }
val TURBINE_TIMEOUT = 5000.toDuration(DurationUnit.MILLISECONDS)
const val MOCKK_TIMEOUT_FOR_VERIFICATION = 1000L

View File

@ -142,14 +142,7 @@ data class LibkiwixBook(
get() = ZimReaderSource(File(path.orEmpty())) get() = ZimReaderSource(File(path.orEmpty()))
// Two books are equal if their ids match // Two books are equal if their ids match
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean = other is LibkiwixBook && other.id == id
if (other is LibkiwixBook) {
if (other.id == id) {
return true
}
}
return false
}
// Only use the book's id to generate a hash code // Only use the book's id to generate a hash code
override fun hashCode(): Int = id.hashCode() override fun hashCode(): Int = id.hashCode()