Added migration test cases for migrating the objectBox data to libkiwix.

* Fixed: `ImportBookmarkTest` which was failing on CI.
* Refactored UI and unit test cases according to the new codebase.
* Fixed: Selecting a ZIM file would select all ZIM files displayed on the Local Library screen.
* Fixed: `network result & language db results activate a combined network + db result`, `library marks files over 4GB as can't download if file system state says to` and `books found on filesystem are filtered by books already in db`, which sometimes fails on the CI.
This commit is contained in:
MohitMaliFtechiz 2025-06-12 00:18:50 +05:30
parent 42da475867
commit c2d35e17d4
11 changed files with 268 additions and 88 deletions

View File

@ -39,9 +39,11 @@ import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertTrue
import org.kiwix.kiwixmobile.core.CoreApp
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity
import org.kiwix.kiwixmobile.core.dao.entities.BookmarkEntity
import org.kiwix.kiwixmobile.core.data.remote.ObjectBoxToLibkiwixMigrator
import org.kiwix.kiwixmobile.core.di.modules.DatabaseModule
import org.kiwix.kiwixmobile.core.entity.LibkiwixBook
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.utils.LanguageUtils.Companion.handleLocaleChange
@ -51,6 +53,7 @@ import org.kiwix.kiwixmobile.testutils.RetryRule
import org.kiwix.kiwixmobile.testutils.TestUtils
import org.kiwix.kiwixmobile.utils.KiwixIdlingResource
import org.kiwix.libkiwix.Book
import org.kiwix.libzim.Archive
import java.io.File
import java.io.FileOutputStream
import java.io.OutputStream
@ -62,7 +65,8 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
// take the existing boxStore object
private var boxStore: BoxStore? = null
private lateinit var zimFile: File
private lateinit var box: Box<BookmarkEntity>
private lateinit var bookOnDiskBox: Box<BookOnDiskEntity>
private lateinit var bookmarkBox: Box<BookmarkEntity>
private val expectedZimName = "Alpine_Linux"
private val expectedZimId = "60094d1e-1c9a-a60b-2011-4fb02f8db6c3"
private val expectedZimFilePath: String by lazy { zimFile.canonicalPath }
@ -82,6 +86,27 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
)
}
private val bookOnDiskEntity: BookOnDiskEntity by lazy {
BookOnDiskEntity(
id = 0,
file = zimFile,
zimReaderSource = ZimReaderSource(zimFile),
bookId = expectedZimId,
title = "",
description = "",
language = "",
creator = "",
publisher = "",
date = "",
url = "",
articleCount = "",
mediaCount = "",
size = "",
name = expectedZimName,
favIcon = ""
)
}
@Rule
@JvmField
var retryRule = RetryRule()
@ -128,18 +153,26 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
" check is your application running"
)
}
box = boxStore!!.boxFor(BookmarkEntity::class.java)
bookmarkBox = boxStore!!.boxFor(BookmarkEntity::class.java)
// clear the data before running the test case
runBlocking { clearBookmarks() }
bookOnDiskBox = boxStore!!.boxFor(BookOnDiskEntity::class.java)
// clear the data before running the test case
runBlocking { clearBookOnDisk() }
// add a file in fileSystem because we need to actual file path for making object of Archive.
zimFile = getZimFile("testzim.zim")
}
private fun getZimFile(zimFileName: String): File {
val loadFileStream =
ObjectBoxToLibkiwixMigratorTest::class.java.classLoader.getResourceAsStream("testzim.zim")
zimFile =
ObjectBoxToLibkiwixMigratorTest::class.java.classLoader.getResourceAsStream(zimFileName)
val zimFile =
File(
context.getExternalFilesDirs(null)[0],
"testzim.zim"
zimFileName
)
if (zimFile.exists()) zimFile.delete()
zimFile.createNewFile()
@ -153,15 +186,16 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
}
}
}
return zimFile
}
@Test
fun testSingleDataMigration(): Unit =
runBlocking {
box.put(bookmarkEntity)
// migrate data into room database
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
// check if data successfully migrated to room
bookmarkBox.put(bookmarkEntity)
// migrate data into room libkiwix.
objectBoxToLibkiwixMigrator.migrateBookMarks(bookmarkBox)
// check if data successfully migrated to libkiwix.
val actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
assertEquals(1, actualDataAfterMigration.size)
@ -173,11 +207,89 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
clearBookmarks()
}
@Test
fun migrateBookOnDisk_ShouldInsertDataInLibkiwix(): Unit =
runBlocking {
// test with single entity
bookOnDiskBox.put(bookOnDiskEntity)
// migrate data into libkiwix
objectBoxToLibkiwixMigrator.migrateLocalBooks(bookOnDiskBox)
// check if data successfully migrated to libkiwix.
var actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookOnDisk.getBooks()
assertEquals(1, actualDataAfterMigration.size)
assertEquals(
actualDataAfterMigration[0].book.zimReaderSource.toDatabase(),
expectedZimFilePath
)
assertEquals(actualDataAfterMigration[0].book.id, expectedZimId)
assertEquals(actualDataAfterMigration[0].book.title, "Test_Zim")
// Clear the bookOnDisk list from device to not affect the other test cases.
clearBookOnDisk()
// test with empty data
objectBoxToLibkiwixMigrator.migrateLocalBooks(bookOnDiskBox)
// check if data successfully migrated to libkiwix.
actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookOnDisk.getBooks()
assertTrue(actualDataAfterMigration.isEmpty())
// Clear the bookOnDisk list from device to not affect the other test cases.
clearBookOnDisk()
// Test if data successfully migrated to libkiwix and existing data is preserved
zimFile = getZimFile("testzim.zim")
val secondZimFile = getZimFile("small.zim")
val archive = Archive(secondZimFile.path)
val book = Book().apply {
update(archive)
}
objectBoxToLibkiwixMigrator.libkiwixBookOnDisk.insert(listOf(book))
val thirdZim = getZimFile("characters_encoding.zim")
val thirdEntity = BookOnDiskEntity(
id = 0,
file = thirdZim,
zimReaderSource = ZimReaderSource(thirdZim),
bookId = expectedZimId,
title = "",
description = "",
language = "",
creator = "",
publisher = "",
date = "",
url = "",
articleCount = "",
mediaCount = "",
size = "",
name = expectedZimName,
favIcon = ""
)
bookOnDiskBox.put(thirdEntity)
bookOnDiskBox.put(bookOnDiskEntity)
// Migrate data into libkiwix
objectBoxToLibkiwixMigrator.migrateLocalBooks(bookOnDiskBox)
actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookOnDisk.getBooks()
assertEquals(3, actualDataAfterMigration.size)
val existingItem =
actualDataAfterMigration.find {
it.book.zimReaderSource.toDatabase() == secondZimFile.path
}
assertNotNull(existingItem)
val newItem =
actualDataAfterMigration.find {
it.book.zimReaderSource.toDatabase() == expectedZimFilePath
}
assertNotNull(newItem)
// Clear the bookmarks list from device to not affect the other test cases.
clearBookmarks()
secondZimFile.delete()
}
@Test
fun testMigrationWithEmptyData(): Unit =
runBlocking {
// Migrate data from empty ObjectBox database
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
objectBoxToLibkiwixMigrator.migrateBookMarks(bookmarkBox)
val actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
assertTrue(actualDataAfterMigration.isEmpty())
@ -209,9 +321,9 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
libkiwixBook
)
)
box.put(bookmarkEntity)
// Migrate data into Room database
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
bookmarkBox.put(bookmarkEntity)
// Migrate data into libkiwix
objectBoxToLibkiwixMigrator.migrateBookMarks(bookmarkBox)
val actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
assertEquals(2, actualDataAfterMigration.size)
@ -234,7 +346,7 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
runBlocking {
// Test large data migration for recent searches
for (i in 1..1000) {
box.put(
bookmarkBox.put(
BookmarkEntity(
0,
expectedZimId,
@ -247,9 +359,9 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
)
)
}
// Migrate data into Room database
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
// Check if data successfully migrated to Room
// Migrate data into libkiwix
objectBoxToLibkiwixMigrator.migrateBookMarks(bookmarkBox)
// Check if data successfully migrated to libkiwix
val actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
assertEquals(1000, actualDataAfterMigration.size)
@ -272,10 +384,10 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
expectedTitle,
expectedFavicon
)
box.put(bookmarkEntity)
// migrate data into room database
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
// check if data successfully migrated to room
bookmarkBox.put(bookmarkEntity)
// migrate data into libkiwix
objectBoxToLibkiwixMigrator.migrateBookMarks(bookmarkBox)
// check if data successfully migrated to libkiwix
val actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
assertEquals(1, actualDataAfterMigration.size)
@ -303,10 +415,10 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
expectedTitle,
expectedFavicon
)
box.put(bookmarkEntity)
// migrate data into room database
objectBoxToLibkiwixMigrator.migrateBookMarks(box)
// check if data successfully migrated to room
bookmarkBox.put(bookmarkEntity)
// migrate data into libkiwix
objectBoxToLibkiwixMigrator.migrateBookMarks(bookmarkBox)
// check if data successfully migrated to libkiwix
val actualDataAfterMigration =
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks().first()
assertEquals(1, actualDataAfterMigration.size)
@ -318,13 +430,24 @@ class ObjectBoxToLibkiwixMigratorTest : BaseActivityTest() {
clearBookmarks()
}
private suspend fun clearBookOnDisk() {
objectBoxToLibkiwixMigrator.libkiwixBookOnDisk.delete(
objectBoxToLibkiwixMigrator.libkiwixBookOnDisk.getBooks()
.map { LibkiwixBook(it.book.nativeBook) }
)
bookOnDiskBox.removeAll()
if (::zimFile.isInitialized) {
zimFile.delete() // delete the temp ZIM file to free up the memory
}
}
private suspend fun clearBookmarks() {
// delete bookmarks for testing other edge cases
objectBoxToLibkiwixMigrator.libkiwixBookmarks.deleteBookmarks(
objectBoxToLibkiwixMigrator.libkiwixBookmarks.bookmarks()
.first() as List<LibkiwixBookmarkItem>
)
box.removeAll()
bookmarkBox.removeAll()
if (::zimFile.isInitialized) {
zimFile.delete() // delete the temp ZIM file to free up the memory
}

View File

@ -40,9 +40,8 @@ import org.junit.Rule
import org.junit.Test
import org.junit.jupiter.api.Assertions.assertEquals
import org.kiwix.kiwixmobile.BaseActivityTest
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks
import org.kiwix.kiwixmobile.core.dao.NewBookDao
import org.kiwix.kiwixmobile.core.dao.entities.BookOnDiskEntity
import org.kiwix.kiwixmobile.core.di.modules.DatabaseModule
import org.kiwix.kiwixmobile.core.page.bookmark.adapter.LibkiwixBookmarkItem
import org.kiwix.kiwixmobile.core.utils.LanguageUtils
@ -63,7 +62,7 @@ class ImportBookmarkTest : BaseActivityTest() {
private var boxStore: BoxStore? = null
private val library = Library()
private val manager = Manager(library)
private lateinit var newBookDao: NewBookDao
private lateinit var libkiwixBookOnDisk: LibkiwixBookOnDisk
private lateinit var libkiwixBookmarks: LibkiwixBookmarks
private val bookmarkXmlData =
@ -138,13 +137,14 @@ class ImportBookmarkTest : BaseActivityTest() {
}
}
boxStore = DatabaseModule.boxStore
newBookDao = NewBookDao(boxStore!!.boxFor(BookOnDiskEntity::class.java))
val sharedPreferenceUtils = SharedPreferenceUtil(context)
libkiwixBookOnDisk = LibkiwixBookOnDisk(library, manager, sharedPreferenceUtils)
libkiwixBookmarks =
LibkiwixBookmarks(
library,
manager,
SharedPreferenceUtil(context),
newBookDao,
sharedPreferenceUtils,
libkiwixBookOnDisk,
null
)
}

View File

@ -28,6 +28,7 @@ import app.cash.turbine.TurbineTestContext
import app.cash.turbine.test
import com.jraska.livedata.test
import io.mockk.clearAllMocks
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
@ -41,9 +42,9 @@ import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.resetMain
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import kotlinx.coroutines.test.setMain
import kotlinx.coroutines.withTimeout
import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.AfterAll
import org.junit.jupiter.api.BeforeEach
@ -129,8 +130,8 @@ class ZimManageViewModelTest {
@AfterAll
fun teardown() {
Dispatchers.resetMain()
viewModel.onClearedExposed()
Dispatchers.resetMain()
}
@BeforeEach
@ -236,24 +237,24 @@ class ZimManageViewModelTest {
@Test
fun `books found on filesystem are filtered by books already in db`() = runTest {
every { application.getString(any()) } returns ""
val expectedBook = libkiwixBook("1")
val bookToRemove = libkiwixBook("2")
val expectedBook = bookOnDisk(1L, libkiwixBook("1", nativeBook = BookTestWrapper("1")))
val bookToRemove = bookOnDisk(1L, libkiwixBook("2", nativeBook = BookTestWrapper("2")))
advanceUntilIdle()
viewModel.requestFileSystemCheck.emit(Unit)
advanceUntilIdle()
// books.emit(listOf(bookToRemove))
// advanceUntilIdle()
// booksOnFileSystem.emit(
// listOf(
// expectedBook,
// expectedBook,
// bookToRemove
// )
// )
// advanceUntilIdle()
// coVerify {
// libkiwixBookOnDisk.insert(listOf(expectedBook.book))
// }
books.emit(listOf(bookToRemove))
advanceUntilIdle()
booksOnFileSystem.emit(
listOfNotNull(
expectedBook.book.nativeBook,
expectedBook.book.nativeBook,
bookToRemove.book.nativeBook
)
)
advanceUntilIdle()
coVerify(timeout = 500) {
libkiwixBookOnDisk.insert(listOfNotNull(expectedBook.book.nativeBook))
}
}
}
@ -358,7 +359,7 @@ class ZimManageViewModelTest {
language(isActive = true, occurencesOfLanguage = 1)
)
advanceUntilIdle()
verify {
verify(timeout = 500) {
newLanguagesDao.insert(
listOf(
dbLanguage.copy(occurencesOfLanguage = 2),
@ -384,9 +385,9 @@ class ZimManageViewModelTest {
every { application.getString(any(), any()) } returns ""
every { defaultLanguageProvider.provide() } returns defaultLanguage
viewModel.networkLibrary.emit(networkBooks)
runCurrent()
advanceUntilIdle()
languages.value = dbBooks
runCurrent()
advanceUntilIdle()
networkStates.value = CONNECTED
advanceUntilIdle()
}
@ -475,13 +476,21 @@ class ZimManageViewModelTest {
viewModel.networkLibrary.emit(listOf(bookOver4Gb))
},
assert = {
skipItems(1)
assertThat(awaitItem()).isEqualTo(
listOf(
LibraryListItem.DividerItem(Long.MIN_VALUE, R.string.other_languages),
LibraryListItem.BookItem(bookOver4Gb, CannotWrite4GbFile)
)
)
withTimeout(5000) {
while (true) {
val item = awaitItem()
val bookItem = item.filterIsInstance<LibraryListItem.BookItem>().firstOrNull()
if (bookItem?.fileSystemState == CannotWrite4GbFile) {
assertThat(item).isEqualTo(
listOf(
LibraryListItem.DividerItem(Long.MIN_VALUE, R.string.other_languages),
LibraryListItem.BookItem(bookOver4Gb, CannotWrite4GbFile)
)
)
break
}
}
}
}
)
}
@ -610,3 +619,9 @@ suspend fun <T> TestScope.testFlow(
}
job.join()
}
class BookTestWrapper(private val id: String) : Book(0L) {
override fun getId(): String = id
override fun equals(other: Any?): Boolean = other is BookTestWrapper && getId() == other.getId()
override fun hashCode(): Int = getId().hashCode()
}

View File

@ -39,7 +39,8 @@ class StorageObserver @Inject constructor(
private val downloadRoomDao: DownloadRoomDao,
private val fileSearch: FileSearch,
private val zimReaderFactory: ZimFileReader.Factory,
private val libkiwixBookmarks: LibkiwixBookmarks
private val libkiwixBookmarks: LibkiwixBookmarks,
private val libkiwixBookFactory: LibkiwixBookFactory
) {
fun getBooksOnFileSystem(
scanningProgressListener: ScanningProgressListener,
@ -64,7 +65,7 @@ class StorageObserver @Inject constructor(
private suspend fun convertToLibkiwixBook(file: File) =
zimReaderFactory.create(ZimReaderSource(file))
?.let { zimFileReader ->
Book().apply {
libkiwixBookFactory.create().apply {
update(zimFileReader.jniKiwixReader)
}.also {
// add the book to libkiwix library to validate the imported bookmarks
@ -73,3 +74,7 @@ class StorageObserver @Inject constructor(
}
}
}
interface LibkiwixBookFactory {
fun create(): Book
}

View File

@ -205,7 +205,7 @@ class LibkiwixBookOnDisk @Inject constructor(
private suspend fun isInTrashFolder(filePath: String) =
Regex("/\\.Trash/").containsMatchIn(filePath)
private suspend fun delete(books: List<LibkiwixBook>) {
suspend fun delete(books: List<LibkiwixBook>) {
runCatching {
books.forEach {
library.removeBookById(it.id)

View File

@ -25,12 +25,13 @@ import dagger.BindsInstance
import dagger.Component
import kotlinx.coroutines.sync.Mutex
import org.kiwix.kiwixmobile.core.CoreApp
import org.kiwix.kiwixmobile.core.LibkiwixBookFactory
import org.kiwix.kiwixmobile.core.StorageObserver
import org.kiwix.kiwixmobile.core.dao.DownloadRoomDao
import org.kiwix.kiwixmobile.core.dao.HistoryDao
import org.kiwix.kiwixmobile.core.dao.HistoryRoomDao
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks
import org.kiwix.kiwixmobile.core.dao.NewBookDao
import org.kiwix.kiwixmobile.core.dao.NewBookmarksDao
import org.kiwix.kiwixmobile.core.dao.NewLanguagesDao
@ -85,6 +86,7 @@ interface CoreComponent {
fun zimReaderContainer(): ZimReaderContainer
fun sharedPrefUtil(): SharedPreferenceUtil
fun zimFileReaderFactory(): ZimFileReader.Factory
fun libkiwixBookFactory(): LibkiwixBookFactory
fun storageObserver(): StorageObserver
fun kiwixService(): KiwixService
fun application(): Application

View File

@ -20,10 +20,12 @@ package org.kiwix.kiwixmobile.core.di.modules
import android.content.Context
import dagger.Module
import dagger.Provides
import org.kiwix.kiwixmobile.core.LibkiwixBookFactory
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookmarks
import org.kiwix.kiwixmobile.core.reader.ZimReaderContainer
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.libkiwix.Book
import org.kiwix.libkiwix.JNIKiwix
import org.kiwix.libkiwix.Library
import org.kiwix.libkiwix.Manager
@ -83,6 +85,14 @@ class JNIModule {
@Named(LOCAL_BOOKS_MANAGER) manager: Manager,
sharedPreferenceUtil: SharedPreferenceUtil,
): LibkiwixBookOnDisk = LibkiwixBookOnDisk(library, manager, sharedPreferenceUtil)
/**
* We are not making this singleton because we need multiple objects of this.
*/
@Provides
fun provideBookFactory(): LibkiwixBookFactory = object : LibkiwixBookFactory {
override fun create(): Book = Book()
}
}
const val BOOKMARK_LIBRARY = "bookmarkLibrary"

View File

@ -29,7 +29,7 @@ import java.io.File
*/
@Suppress("ConstructorParameterNaming")
data class LibkiwixBook(
val nativeBook: Book? = null,
var nativeBook: Book? = null,
private var _id: String = "",
private var _title: String = "",
private var _description: String? = null,

View File

@ -35,6 +35,7 @@ import org.kiwix.kiwixmobile.core.entity.MetaLinkNetworkEntity.Url
import org.kiwix.kiwixmobile.core.reader.ZimReaderSource
import org.kiwix.kiwixmobile.core.zim_manager.Language
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
import org.kiwix.libkiwix.Book
import java.io.File
fun bookOnDisk(
@ -146,8 +147,11 @@ fun libkiwixBook(
size: String = "1024",
name: String = "name",
favIcon: String = "favIcon",
file: File = File("")
file: File = File(""),
nativeBook: Book? = null,
tags: String? = ""
) = LibkiwixBook().apply {
this.nativeBook = nativeBook
this.id = id
this.title = title
this.description = description
@ -162,6 +166,7 @@ fun libkiwixBook(
this.file = file
bookName = name
favicon = favIcon
this.tags = tags
}
fun recentSearchEntity(

View File

@ -19,6 +19,8 @@
package org.kiwix.kiwixmobile.core
import io.mockk.clearAllMocks
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
@ -39,9 +41,9 @@ import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
import org.kiwix.kiwixmobile.core.utils.files.FileSearch
import org.kiwix.kiwixmobile.core.utils.files.ScanningProgressListener
import org.kiwix.kiwixmobile.core.utils.files.testFlow
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.BooksOnDiskListItem.BookOnDisk
import org.kiwix.libkiwix.Book
import org.kiwix.libzim.Archive
import org.kiwix.sharedFunctions.libkiwixBook
import org.kiwix.sharedFunctions.bookOnDisk
import java.io.File
class StorageObserverTest {
@ -58,6 +60,8 @@ class StorageObserverTest {
private val files = MutableStateFlow<List<File>>(emptyList())
private val downloads = MutableStateFlow<List<DownloadModel>>(emptyList())
private val libkiwixBookFactory: LibkiwixBookFactory = mockk()
private val libkiwixBook: Book = BookTestWrapper("id")
private lateinit var storageObserver: StorageObserver
@ -66,9 +70,17 @@ class StorageObserverTest {
every { sharedPreferenceUtil.prefStorage } returns "a"
every { fileSearch.scan(scanningProgressListener) } returns files
every { downloadRoomDao.downloads() } returns downloads
coEvery { libkiwixBookmarks.addBookToLibrary(any()) } returns Unit
every { zimFileReader.jniKiwixReader } returns mockk()
every { runBlocking { readerFactory.create(zimReaderSource) } } returns zimFileReader
storageObserver = StorageObserver(downloadRoomDao, fileSearch, readerFactory, libkiwixBookmarks)
every { libkiwixBookFactory.create() } returns libkiwixBook
storageObserver = StorageObserver(
downloadRoomDao,
fileSearch,
readerFactory,
libkiwixBookmarks,
libkiwixBookFactory
)
}
@Test
@ -77,7 +89,7 @@ class StorageObserverTest {
testFlow(
flow = booksOnFileSystem(),
triggerAction = {},
assert = { assertThat(awaitItem()).isEqualTo(listOf<BookOnDisk>()) }
assert = { assertThat(awaitItem()).isEqualTo(listOf<Book>()) }
)
}
@ -87,7 +99,7 @@ class StorageObserverTest {
val expectedBook =
libkiwixBook(
"id", "title", "1", "favicon", "creator", "publisher", "date",
"description", "language"
"description", "language", nativeBook = libkiwixBook
)
withNoFiltering()
every { zimFileReader.toBook() } returns expectedBook
@ -97,15 +109,14 @@ class StorageObserverTest {
triggerAction = {},
assert = {
assertThat(awaitItem()).isEqualTo(
listOf<BookOnDisk>(
bookOnDisk(
book = expectedBook,
zimReaderSource = zimReaderSource
)
listOfNotNull<Book>(
expectedBook.nativeBook
)
)
}
)
// test the book is added to bookmark's library.
coVerify { libkiwixBookmarks.addBookToLibrary(archive = any()) }
verify { zimFileReader.dispose() }
}
@ -128,3 +139,12 @@ class StorageObserverTest {
every { zimReaderSource.file } returns file
}
}
class BookTestWrapper(private val id: String) : Book(0L) {
override fun getId(): String = id
override fun equals(other: Any?): Boolean = other is BookTestWrapper && getId() == other.getId()
override fun hashCode(): Int = getId().hashCode()
override fun update(archive: Archive?) {
// do nothing
}
}

View File

@ -36,7 +36,7 @@ import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import org.kiwix.kiwixmobile.core.compat.CompatHelper.Companion.getPackageInformation
import org.kiwix.kiwixmobile.core.dao.NewBookDao
import org.kiwix.kiwixmobile.core.dao.LibkiwixBookOnDisk
import org.kiwix.kiwixmobile.core.downloader.downloadManager.ZERO
import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions
@ -44,7 +44,7 @@ import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions
class DonationDialogHandlerTest {
private lateinit var activity: Activity
private lateinit var sharedPreferenceUtil: SharedPreferenceUtil
private lateinit var newBookDao: NewBookDao
private lateinit var libkiwixBookOnDisk: LibkiwixBookOnDisk
private lateinit var donationDialogHandler: DonationDialogHandler
private lateinit var showDonationDialogCallback: DonationDialogHandler.ShowDonationDialogCallback
private lateinit var packageManager: PackageManager
@ -56,10 +56,10 @@ class DonationDialogHandlerTest {
every { activity.packageManager } returns packageManager
every { activity.packageName } returns "org.kiwix.kiwixmobile"
sharedPreferenceUtil = mockk(relaxed = true)
newBookDao = mockk(relaxed = true)
libkiwixBookOnDisk = mockk(relaxed = true)
showDonationDialogCallback = mockk(relaxed = true)
donationDialogHandler =
DonationDialogHandler(activity, sharedPreferenceUtil, newBookDao)
DonationDialogHandler(activity, sharedPreferenceUtil, libkiwixBookOnDisk)
donationDialogHandler.setDonationDialogCallBack(showDonationDialogCallback)
}
@ -69,7 +69,7 @@ class DonationDialogHandlerTest {
donationDialogHandler = spyk(donationDialogHandler)
every { sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds } returns 0L
every { sharedPreferenceUtil.laterClickedMilliSeconds } returns 0L
coEvery { newBookDao.getBooks() } returns listOf(mockk())
coEvery { libkiwixBookOnDisk.getBooks() } returns listOf(mockk())
every {
donationDialogHandler.shouldShowInitialPopup(any())
} returns true
@ -81,7 +81,7 @@ class DonationDialogHandlerTest {
fun `should not show donation popup if app is not three month old`() =
runTest {
every { sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds } returns 0L
coEvery { newBookDao.getBooks() } returns listOf(mockk())
coEvery { libkiwixBookOnDisk.getBooks() } returns listOf(mockk())
val currentMillis = System.currentTimeMillis()
val installTime = currentMillis - 1000
val packageInfo =
@ -99,7 +99,7 @@ class DonationDialogHandlerTest {
fun `should not show donation popup when no ZIM files available in library`() =
runTest {
every { sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds } returns 0L
coEvery { newBookDao.getBooks() } returns emptyList()
coEvery { libkiwixBookOnDisk.getBooks() } returns emptyList()
val currentMillis = System.currentTimeMillis()
val threeMonthsAgo = currentMillis - THREE_MONTHS_IN_MILLISECONDS
val packageInfo =
@ -119,7 +119,7 @@ class DonationDialogHandlerTest {
every {
sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds
} returns currentMilliSeconds - (THREE_MONTHS_IN_MILLISECONDS / 2)
coEvery { newBookDao.getBooks() } returns listOf(mockk())
coEvery { libkiwixBookOnDisk.getBooks() } returns listOf(mockk())
donationDialogHandler.attemptToShowDonationPopup()
verify(exactly = 0) { showDonationDialogCallback.showDonationDialog() }
}
@ -131,7 +131,7 @@ class DonationDialogHandlerTest {
every {
sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds
} returns currentMilliSeconds - (THREE_MONTHS_IN_MILLISECONDS + 1000)
coEvery { newBookDao.getBooks() } returns listOf(mockk())
coEvery { libkiwixBookOnDisk.getBooks() } returns listOf(mockk())
donationDialogHandler.attemptToShowDonationPopup()
verify { showDonationDialogCallback.showDonationDialog() }
}
@ -145,7 +145,7 @@ class DonationDialogHandlerTest {
sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds
} returns 0L
every { donationDialogHandler.shouldShowInitialPopup(any()) } returns true
coEvery { newBookDao.getBooks() } returns listOf(mockk())
coEvery { libkiwixBookOnDisk.getBooks() } returns listOf(mockk())
every {
sharedPreferenceUtil.laterClickedMilliSeconds
} returns currentMilliSeconds - (THREE_MONTHS_IN_MILLISECONDS + 1000)
@ -162,7 +162,7 @@ class DonationDialogHandlerTest {
sharedPreferenceUtil.lastDonationPopupShownInMilliSeconds
} returns 0L
every { donationDialogHandler.shouldShowInitialPopup(any()) } returns true
coEvery { newBookDao.getBooks() } returns listOf(mockk())
coEvery { libkiwixBookOnDisk.getBooks() } returns listOf(mockk())
every {
sharedPreferenceUtil.laterClickedMilliSeconds
} returns currentMilliSeconds - 10000L
@ -243,7 +243,7 @@ class DonationDialogHandlerTest {
with(mockk<ActivityExtensions>()) {
every { activity.packageName } returns "org.kiwix.kiwixmobile"
every { activity.isCustomApp() } returns false
coEvery { newBookDao.getBooks() } returns emptyList()
coEvery { libkiwixBookOnDisk.getBooks() } returns emptyList()
val result = donationDialogHandler.isZimFilesAvailableInLibrary()
assertFalse(result)
}
@ -255,7 +255,7 @@ class DonationDialogHandlerTest {
with(mockk<ActivityExtensions>()) {
every { activity.packageName } returns "org.kiwix.kiwixmobile"
every { activity.isCustomApp() } returns false
coEvery { newBookDao.getBooks() } returns listOf(mockk())
coEvery { libkiwixBookOnDisk.getBooks() } returns listOf(mockk())
val result = donationDialogHandler.isZimFilesAvailableInLibrary()
assertTrue(result)
}