Unit test for BackupAgent

This commit is contained in:
Koitharu
2022-07-18 11:27:56 +03:00
parent dfa413da6f
commit f0ee64bafa
4 changed files with 183 additions and 9 deletions

View File

@@ -64,8 +64,11 @@ android {
disable 'MissingTranslation', 'PrivateResource', 'NotifyDataSetChanged'
}
testOptions {
unitTests.includeAndroidResources = true
unitTests.returnDefaultValues = false
unitTests.includeAndroidResources true
unitTests.returnDefaultValues false
kotlinOptions {
freeCompilerArgs += ['-opt-in=org.koitharu.kotatsu.parsers.InternalParsersApi']
}
}
}
afterEvaluate {

View File

@@ -0,0 +1,102 @@
package org.koitharu.kotatsu
import org.koitharu.kotatsu.core.model.FavouriteCategory
import org.koitharu.kotatsu.parsers.model.*
import java.util.*
object SampleData {
val manga = Manga(
id = 1105355890252749533,
title = "Sasurai Emanon",
altTitle = null,
url = "/manga/sasurai_emanon/",
publicUrl = "https://www.mangatown.com/manga/sasurai_emanon/",
rating = 1.0f,
isNsfw = false,
coverUrl = "https://fmcdn.mangahere.com/store/manga/10992/ocover.jpg?token=905148d2f052f9d3604135933b958771c8b00077&ttl=1658214000&v=1578490983",
tags = setOf(
MangaTag(title = "Adventure", key = "0-adventure-0-0-0-0", source = MangaSource.MANGATOWN),
MangaTag(title = "Mature", key = "0-mature-0-0-0-0", source = MangaSource.MANGATOWN),
MangaTag(title = "Psychological", key = "0-psychological-0-0-0-0", source = MangaSource.MANGATOWN),
MangaTag(title = "Slice Of Life", key = "0-slice_of_life-0-0-0-0", source = MangaSource.MANGATOWN),
MangaTag(title = "Supernatural", key = "0-supernatural-0-0-0-0", source = MangaSource.MANGATOWN),
),
state = MangaState.ONGOING,
author = "Kajio Shinji",
largeCoverUrl = null,
source = MangaSource.MANGATOWN,
)
val mangaDetails = manga.copy(
tags = setOf(
MangaTag(title = "Adventure", key = "0-adventure-0-0-0-0", source = MangaSource.MANGATOWN),
MangaTag(title = "Mature", key = "0-mature-0-0-0-0", source = MangaSource.MANGATOWN),
MangaTag(title = "Psychological", key = "0-psychological-0-0-0-0", source = MangaSource.MANGATOWN),
MangaTag(title = "Slice Of Life", key = "0-slice_of_life-0-0-0-0", source = MangaSource.MANGATOWN),
MangaTag(title = "Supernatural", key = "0-supernatural-0-0-0-0", source = MangaSource.MANGATOWN),
),
largeCoverUrl = null,
description = """
Based on the award-winning novel by Shinji Kajio, Memories of Emanon tells the story of a mysterious girl
who holds a 3-billion-year old memory, dating back to the moment life first appeared on Earth. The first
half of the volume is the colored Wandering Emanon '67 chapters (published before as Emanon Episode: 1).
The second half is Wandering Emanon set before the '67 chapters.
""".trimIndent(),
chapters = listOf(
MangaChapter(
id = -7214407414868456892,
name = "Sasurai Emanon - 1",
number = 1,
url = "/manga/sasurai_emanon/c001/",
scanlator = null,
uploadDate = 1335906000000,
branch = null,
source = MangaSource.MANGATOWN,
),
MangaChapter(
id = -7214407414868456861,
name = "Sasurai Emanon - 2",
number = 2,
url = "/manga/sasurai_emanon/c002/",
scanlator = null,
uploadDate = 1335906000000,
branch = null,
source = MangaSource.MANGATOWN,
),
MangaChapter(
id = -7214407414868456830,
name = "Sasurai Emanon - 3",
number = 3,
url = "/manga/sasurai_emanon/c003/",
scanlator = null,
uploadDate = 1335906000000,
branch = null,
source = MangaSource.MANGATOWN,
),
MangaChapter(
id = -7214407414868456799,
name = "Sasurai Emanon - 4",
number = 3,
url = "/manga/sasurai_emanon/c004/",
scanlator = null,
uploadDate = 1335906000000,
branch = null,
source = MangaSource.MANGATOWN,
),
),
)
val tag = mangaDetails.tags.elementAt(2)
val chapter = checkNotNull(mangaDetails.chapters)[2]
val favouriteCategory = FavouriteCategory(
id = 4,
title = "Read later",
sortKey = 1,
order = SortOrder.NEWEST,
createdAt = Date(1335906000000),
isTrackingEnabled = true,
)
}

View File

@@ -0,0 +1,67 @@
package org.koitharu.kotatsu.settings.backup
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.coroutines.test.runTest
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.koin.test.KoinTest
import org.koin.test.get
import org.koin.test.inject
import org.koitharu.kotatsu.SampleData
import org.koitharu.kotatsu.core.backup.BackupRepository
import org.koitharu.kotatsu.core.db.MangaDatabase
import org.koitharu.kotatsu.core.db.entity.toMangaTags
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
import org.koitharu.kotatsu.history.domain.HistoryRepository
import kotlin.test.*
@RunWith(AndroidJUnit4::class)
class AppBackupAgentTest : KoinTest {
private val historyRepository by inject<HistoryRepository>()
private val favouritesRepository by inject<FavouritesRepository>()
private val backupRepository by inject<BackupRepository>()
private val database by inject<MangaDatabase>()
@Before
fun setUp() {
database.clearAllTables()
}
@Test
fun testBackupRestore() = runTest {
val category = favouritesRepository.createCategory(
title = SampleData.favouriteCategory.title,
sortOrder = SampleData.favouriteCategory.order,
isTrackerEnabled = SampleData.favouriteCategory.isTrackingEnabled,
)
favouritesRepository.addToCategory(categoryId = category.id, mangas = listOf(SampleData.manga))
historyRepository.addOrUpdate(
manga = SampleData.mangaDetails,
chapterId = SampleData.mangaDetails.chapters!![2].id,
page = 3,
scroll = 40,
percent = 0.2f,
)
val history = checkNotNull(historyRepository.getOne(SampleData.mangaDetails))
val agent = AppBackupAgent()
val backup = agent.createBackupFile(get(), backupRepository)
database.clearAllTables()
assertTrue(favouritesRepository.getAllManga().isEmpty())
assertNull(historyRepository.getLastOrNull())
backup.inputStream().use {
agent.restoreBackupFile(it.fd, backup.length(), backupRepository)
}
assertEquals(category, favouritesRepository.getCategory(category.id))
assertEquals(history, historyRepository.getOne(SampleData.manga))
assertContentEquals(listOf(SampleData.manga), favouritesRepository.getManga(category.id))
val allTags = database.tagsDao.findTags(SampleData.tag.source.name).toMangaTags()
assertContains(allTags, SampleData.tag)
}
}

View File

@@ -4,7 +4,9 @@ import android.app.backup.BackupAgent
import android.app.backup.BackupDataInput
import android.app.backup.BackupDataOutput
import android.app.backup.FullBackupDataOutput
import android.content.Context
import android.os.ParcelFileDescriptor
import androidx.annotation.VisibleForTesting
import kotlinx.coroutines.runBlocking
import org.koitharu.kotatsu.core.backup.BackupEntry
import org.koitharu.kotatsu.core.backup.BackupRepository
@@ -29,7 +31,7 @@ class AppBackupAgent : BackupAgent() {
override fun onFullBackup(data: FullBackupDataOutput) {
super.onFullBackup(data)
val file = createBackupFile()
val file = createBackupFile(this, BackupRepository(MangaDatabase(applicationContext)))
try {
fullBackupFile(file, data)
} finally {
@@ -46,16 +48,16 @@ class AppBackupAgent : BackupAgent() {
mtime: Long
) {
if (destination?.name?.endsWith(".bk.zip") == true) {
restoreBackupFile(data.fileDescriptor, size)
restoreBackupFile(data.fileDescriptor, size, BackupRepository(MangaDatabase(applicationContext)))
destination.delete()
} else {
super.onRestoreFile(data, size, destination, type, mode, mtime)
}
}
private fun createBackupFile() = runBlocking {
val repository = BackupRepository(MangaDatabase(applicationContext))
BackupZipOutput(this@AppBackupAgent).use { backup ->
@VisibleForTesting
fun createBackupFile(context: Context, repository: BackupRepository) = runBlocking {
BackupZipOutput(context).use { backup ->
backup.put(repository.createIndex())
backup.put(repository.dumpHistory())
backup.put(repository.dumpCategories())
@@ -65,8 +67,8 @@ class AppBackupAgent : BackupAgent() {
}
}
private fun restoreBackupFile(fd: FileDescriptor, size: Long) {
val repository = BackupRepository(MangaDatabase(applicationContext))
@VisibleForTesting
fun restoreBackupFile(fd: FileDescriptor, size: Long, repository: BackupRepository) {
val tempFile = File.createTempFile("backup_", ".tmp")
FileInputStream(fd).use { input ->
tempFile.outputStream().use { output ->