Merge branch 'devel' into feature/nextgen
commit
008863fee8
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"title": "Read later",
|
||||||
|
"sortKey": 1,
|
||||||
|
"order": "NEWEST",
|
||||||
|
"createdAt": 1335906000000,
|
||||||
|
"isTrackingEnabled": true
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"id": -2096681732556647985,
|
||||||
|
"title": "Странствия Эманон",
|
||||||
|
"url": "/stranstviia_emanon",
|
||||||
|
"publicUrl": "https://readmanga.io/stranstviia_emanon",
|
||||||
|
"rating": 0.9400894,
|
||||||
|
"isNsfw": true,
|
||||||
|
"coverUrl": "https://staticrm.rmr.rocks/uploads/pics/01/12/559_p.jpg",
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"title": "Сверхъестественное",
|
||||||
|
"key": "supernatural",
|
||||||
|
"source": "READMANGA_RU"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Сэйнэн",
|
||||||
|
"key": "seinen",
|
||||||
|
"source": "READMANGA_RU"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Повседневность",
|
||||||
|
"key": "slice_of_life",
|
||||||
|
"source": "READMANGA_RU"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Приключения",
|
||||||
|
"key": "adventure",
|
||||||
|
"source": "READMANGA_RU"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"state": "FINISHED",
|
||||||
|
"largeCoverUrl": "https://staticrm.rmr.rocks/uploads/pics/01/12/559_o.jpg",
|
||||||
|
"description": null,
|
||||||
|
"source": "READMANGA_RU"
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package org.koitharu.kotatsu
|
||||||
|
|
||||||
|
import android.app.Instrumentation
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
|
suspend fun Instrumentation.awaitForIdle() = suspendCoroutine<Unit> { cont ->
|
||||||
|
waitForIdle { cont.resume(Unit) }
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
package org.koitharu.kotatsu
|
||||||
|
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
import com.squareup.moshi.*
|
||||||
|
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||||
|
import okio.buffer
|
||||||
|
import okio.source
|
||||||
|
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||||
|
import org.koitharu.kotatsu.parsers.model.Manga
|
||||||
|
import java.util.*
|
||||||
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
object SampleData {
|
||||||
|
|
||||||
|
private val moshi = Moshi.Builder()
|
||||||
|
.add(DateAdapter())
|
||||||
|
.add(KotlinJsonAdapterFactory())
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val manga: Manga = loadAsset("manga/header.json", Manga::class)
|
||||||
|
|
||||||
|
val mangaDetails: Manga = loadAsset("manga/full.json", Manga::class)
|
||||||
|
|
||||||
|
val tag = mangaDetails.tags.elementAt(2)
|
||||||
|
|
||||||
|
val chapter = checkNotNull(mangaDetails.chapters)[2]
|
||||||
|
|
||||||
|
val favouriteCategory: FavouriteCategory = loadAsset("categories/simple.json", FavouriteCategory::class)
|
||||||
|
|
||||||
|
fun <T : Any> loadAsset(name: String, cls: KClass<T>): T {
|
||||||
|
val assets = InstrumentationRegistry.getInstrumentation().context.assets
|
||||||
|
return assets.open(name).use {
|
||||||
|
moshi.adapter(cls.java).fromJson(it.source().buffer())
|
||||||
|
} ?: throw RuntimeException("Cannot read asset from json \"$name\"")
|
||||||
|
}
|
||||||
|
|
||||||
|
private class DateAdapter : JsonAdapter<Date>() {
|
||||||
|
|
||||||
|
@FromJson
|
||||||
|
override fun fromJson(reader: JsonReader): Date? {
|
||||||
|
val ms = reader.nextLong()
|
||||||
|
return if (ms == 0L) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
Date(ms)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ToJson
|
||||||
|
override fun toJson(writer: JsonWriter, value: Date?) {
|
||||||
|
writer.value(value?.time ?: 0L)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
package org.koitharu.kotatsu.core.os
|
||||||
|
|
||||||
|
import android.content.pm.ShortcutInfo
|
||||||
|
import android.content.pm.ShortcutManager
|
||||||
|
import androidx.core.content.getSystemService
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
|
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.inject
|
||||||
|
import org.koitharu.kotatsu.SampleData
|
||||||
|
import org.koitharu.kotatsu.awaitForIdle
|
||||||
|
import org.koitharu.kotatsu.core.db.MangaDatabase
|
||||||
|
import org.koitharu.kotatsu.history.domain.HistoryRepository
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4::class)
|
||||||
|
class ShortcutsUpdaterTest : KoinTest {
|
||||||
|
|
||||||
|
private val historyRepository by inject<HistoryRepository>()
|
||||||
|
private val shortcutsUpdater by inject<ShortcutsUpdater>()
|
||||||
|
private val database by inject<MangaDatabase>()
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setUp() {
|
||||||
|
database.clearAllTables()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testUpdateShortcuts() = runTest {
|
||||||
|
awaitUpdate()
|
||||||
|
assertTrue(getShortcuts().isEmpty())
|
||||||
|
historyRepository.addOrUpdate(
|
||||||
|
manga = SampleData.manga,
|
||||||
|
chapterId = SampleData.chapter.id,
|
||||||
|
page = 4,
|
||||||
|
scroll = 2,
|
||||||
|
percent = 0.3f
|
||||||
|
)
|
||||||
|
awaitUpdate()
|
||||||
|
|
||||||
|
val shortcuts = getShortcuts()
|
||||||
|
assertEquals(1, shortcuts.size)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getShortcuts(): List<ShortcutInfo> {
|
||||||
|
val context = InstrumentationRegistry.getInstrumentation().targetContext
|
||||||
|
val manager = checkNotNull(context.getSystemService<ShortcutManager>())
|
||||||
|
return manager.dynamicShortcuts.filterNot { it.id == "com.squareup.leakcanary.dynamic_shortcut" }
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun awaitUpdate() {
|
||||||
|
val instrumentation = InstrumentationRegistry.getInstrumentation()
|
||||||
|
while (true) {
|
||||||
|
instrumentation.awaitForIdle()
|
||||||
|
if (shortcutsUpdater.await()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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.manga))
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
package org.koitharu.kotatsu.core.backup
|
||||||
|
|
||||||
|
import org.json.JSONObject
|
||||||
|
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||||
|
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||||
|
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||||
|
import org.koitharu.kotatsu.favourites.data.FavouriteEntity
|
||||||
|
import org.koitharu.kotatsu.history.data.HistoryEntity
|
||||||
|
|
||||||
|
class JsonSerializer private constructor(private val json: JSONObject) {
|
||||||
|
|
||||||
|
constructor(e: FavouriteEntity) : this(
|
||||||
|
JSONObject().apply {
|
||||||
|
put("manga_id", e.mangaId)
|
||||||
|
put("category_id", e.categoryId)
|
||||||
|
put("sort_key", e.sortKey)
|
||||||
|
put("created_at", e.createdAt)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
constructor(e: FavouriteCategoryEntity) : this(
|
||||||
|
JSONObject().apply {
|
||||||
|
put("category_id", e.categoryId)
|
||||||
|
put("created_at", e.createdAt)
|
||||||
|
put("sort_key", e.sortKey)
|
||||||
|
put("title", e.title)
|
||||||
|
put("order", e.order)
|
||||||
|
put("track", e.track)
|
||||||
|
put("show_in_lib", e.isVisibleInLibrary)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
constructor(e: HistoryEntity) : this(
|
||||||
|
JSONObject().apply {
|
||||||
|
put("manga_id", e.mangaId)
|
||||||
|
put("created_at", e.createdAt)
|
||||||
|
put("updated_at", e.updatedAt)
|
||||||
|
put("chapter_id", e.chapterId)
|
||||||
|
put("page", e.page)
|
||||||
|
put("scroll", e.scroll)
|
||||||
|
put("percent", e.percent)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
constructor(e: TagEntity) : this(
|
||||||
|
JSONObject().apply {
|
||||||
|
put("id", e.id)
|
||||||
|
put("title", e.title)
|
||||||
|
put("key", e.key)
|
||||||
|
put("source", e.source)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
constructor(e: MangaEntity) : this(
|
||||||
|
JSONObject().apply {
|
||||||
|
put("id", e.id)
|
||||||
|
put("title", e.title)
|
||||||
|
put("alt_title", e.altTitle)
|
||||||
|
put("url", e.url)
|
||||||
|
put("public_url", e.publicUrl)
|
||||||
|
put("rating", e.rating)
|
||||||
|
put("nsfw", e.isNsfw)
|
||||||
|
put("cover_url", e.coverUrl)
|
||||||
|
put("large_cover_url", e.largeCoverUrl)
|
||||||
|
put("state", e.state)
|
||||||
|
put("author", e.author)
|
||||||
|
put("source", e.source)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
fun toJson(): JSONObject = json
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
package org.koitharu.kotatsu.core.db
|
||||||
|
|
||||||
|
|
||||||
|
const val TABLE_FAVOURITES = "favourites"
|
||||||
|
const val TABLE_MANGA = "manga"
|
||||||
|
const val TABLE_TAGS = "tags"
|
||||||
|
const val TABLE_FAVOURITE_CATEGORIES = "favourite_categories"
|
||||||
|
const val TABLE_HISTORY = "history"
|
||||||
|
const val TABLE_MANGA_TAGS = "manga_tags"
|
||||||
@ -1,19 +1,29 @@
|
|||||||
package org.koitharu.kotatsu.main
|
package org.koitharu.kotatsu.main
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.room.InvalidationTracker
|
||||||
import org.koin.android.ext.koin.androidContext
|
import org.koin.android.ext.koin.androidContext
|
||||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||||
|
import org.koin.dsl.bind
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
import org.koitharu.kotatsu.base.ui.util.ActivityRecreationHandle
|
import org.koitharu.kotatsu.base.ui.util.ActivityRecreationHandle
|
||||||
import org.koitharu.kotatsu.core.os.ShortcutsRepository
|
import org.koitharu.kotatsu.core.os.ShortcutsUpdater
|
||||||
import org.koitharu.kotatsu.main.ui.MainViewModel
|
import org.koitharu.kotatsu.main.ui.MainViewModel
|
||||||
import org.koitharu.kotatsu.main.ui.protect.AppProtectHelper
|
import org.koitharu.kotatsu.main.ui.protect.AppProtectHelper
|
||||||
import org.koitharu.kotatsu.main.ui.protect.ProtectViewModel
|
import org.koitharu.kotatsu.main.ui.protect.ProtectViewModel
|
||||||
|
|
||||||
val mainModule
|
val mainModule
|
||||||
get() = module {
|
get() = module {
|
||||||
single { AppProtectHelper(get()) }
|
single { AppProtectHelper(get()) } bind Application.ActivityLifecycleCallbacks::class
|
||||||
single { ActivityRecreationHandle() }
|
single { ActivityRecreationHandle() } bind Application.ActivityLifecycleCallbacks::class
|
||||||
factory { ShortcutsRepository(androidContext(), get(), get(), get()) }
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
|
||||||
|
single { ShortcutsUpdater(androidContext(), get(), get(), get()) } bind InvalidationTracker.Observer::class
|
||||||
|
} else {
|
||||||
|
factory { ShortcutsUpdater(androidContext(), get(), get(), get()) }
|
||||||
|
}
|
||||||
|
|
||||||
viewModel { MainViewModel(get(), get()) }
|
viewModel { MainViewModel(get(), get()) }
|
||||||
viewModel { ProtectViewModel(get(), get()) }
|
viewModel { ProtectViewModel(get(), get()) }
|
||||||
}
|
}
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.backup
|
||||||
|
|
||||||
|
import android.app.backup.BackupManager
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import androidx.room.InvalidationTracker
|
||||||
|
import org.koitharu.kotatsu.core.db.TABLE_FAVOURITES
|
||||||
|
import org.koitharu.kotatsu.core.db.TABLE_FAVOURITE_CATEGORIES
|
||||||
|
import org.koitharu.kotatsu.core.db.TABLE_HISTORY
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.M)
|
||||||
|
class BackupObserver(
|
||||||
|
context: Context,
|
||||||
|
) : InvalidationTracker.Observer(arrayOf(TABLE_HISTORY, TABLE_FAVOURITES, TABLE_FAVOURITE_CATEGORIES)) {
|
||||||
|
|
||||||
|
private val backupManager = BackupManager(context)
|
||||||
|
|
||||||
|
override fun onInvalidated(tables: MutableSet<String>) {
|
||||||
|
backupManager.dataChanged()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,15 @@
|
|||||||
package org.koitharu.kotatsu.widget
|
package org.koitharu.kotatsu.widget
|
||||||
|
|
||||||
|
import androidx.room.InvalidationTracker
|
||||||
|
import org.koin.android.ext.koin.androidContext
|
||||||
import org.koin.androidx.viewmodel.dsl.viewModel
|
import org.koin.androidx.viewmodel.dsl.viewModel
|
||||||
import org.koin.dsl.module
|
import org.koin.dsl.module
|
||||||
import org.koitharu.kotatsu.widget.shelf.ShelfConfigViewModel
|
import org.koitharu.kotatsu.widget.shelf.ShelfConfigViewModel
|
||||||
|
|
||||||
val appWidgetModule
|
val appWidgetModule
|
||||||
get() = module {
|
get() = module {
|
||||||
|
|
||||||
|
single<InvalidationTracker.Observer> { WidgetUpdater(androidContext()) }
|
||||||
|
|
||||||
viewModel { ShelfConfigViewModel(get()) }
|
viewModel { ShelfConfigViewModel(get()) }
|
||||||
}
|
}
|
||||||
@ -0,0 +1,95 @@
|
|||||||
|
package org.koitharu.kotatsu.core.backup
|
||||||
|
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Test
|
||||||
|
import org.koitharu.kotatsu.core.db.entity.MangaEntity
|
||||||
|
import org.koitharu.kotatsu.core.db.entity.TagEntity
|
||||||
|
import org.koitharu.kotatsu.favourites.data.FavouriteCategoryEntity
|
||||||
|
import org.koitharu.kotatsu.favourites.data.FavouriteEntity
|
||||||
|
import org.koitharu.kotatsu.history.data.HistoryEntity
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
import org.koitharu.kotatsu.parsers.model.MangaState
|
||||||
|
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
class JsonSerializerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toFavouriteEntity() {
|
||||||
|
val entity = FavouriteEntity(
|
||||||
|
mangaId = 40,
|
||||||
|
categoryId = 20,
|
||||||
|
sortKey = 1,
|
||||||
|
createdAt = System.currentTimeMillis(),
|
||||||
|
)
|
||||||
|
val json = JsonSerializer(entity).toJson()
|
||||||
|
val result = JsonDeserializer(json).toFavouriteEntity()
|
||||||
|
assertEquals(entity, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toMangaEntity() {
|
||||||
|
val entity = MangaEntity(
|
||||||
|
id = 231,
|
||||||
|
title = "Lorem Ipsum",
|
||||||
|
altTitle = "Lorem Ispum 2",
|
||||||
|
url = "erw",
|
||||||
|
publicUrl = "hthth",
|
||||||
|
rating = 0.78f,
|
||||||
|
isNsfw = true,
|
||||||
|
coverUrl = "5345",
|
||||||
|
largeCoverUrl = null,
|
||||||
|
state = MangaState.FINISHED.name,
|
||||||
|
author = "RERE",
|
||||||
|
source = MangaSource.DUMMY.name,
|
||||||
|
)
|
||||||
|
val json = JsonSerializer(entity).toJson()
|
||||||
|
val result = JsonDeserializer(json).toMangaEntity()
|
||||||
|
assertEquals(entity, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toTagEntity() {
|
||||||
|
val entity = TagEntity(
|
||||||
|
id = 934023534,
|
||||||
|
title = "Adventure",
|
||||||
|
key = "adventure",
|
||||||
|
source = MangaSource.DUMMY.name,
|
||||||
|
)
|
||||||
|
val json = JsonSerializer(entity).toJson()
|
||||||
|
val result = JsonDeserializer(json).toTagEntity()
|
||||||
|
assertEquals(entity, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toHistoryEntity() {
|
||||||
|
val entity = HistoryEntity(
|
||||||
|
mangaId = 304135341,
|
||||||
|
createdAt = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(6),
|
||||||
|
updatedAt = System.currentTimeMillis(),
|
||||||
|
chapterId = 29014843034,
|
||||||
|
page = 35,
|
||||||
|
scroll = 24.0f,
|
||||||
|
percent = 0.6f,
|
||||||
|
)
|
||||||
|
val json = JsonSerializer(entity).toJson()
|
||||||
|
val result = JsonDeserializer(json).toHistoryEntity()
|
||||||
|
assertEquals(entity, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun toFavouriteCategoryEntity() {
|
||||||
|
val entity = FavouriteCategoryEntity(
|
||||||
|
categoryId = 142,
|
||||||
|
createdAt = System.currentTimeMillis(),
|
||||||
|
sortKey = 14,
|
||||||
|
title = "Read later",
|
||||||
|
order = SortOrder.RATING.name,
|
||||||
|
track = false,
|
||||||
|
isVisibleInLibrary = true,
|
||||||
|
)
|
||||||
|
val json = JsonSerializer(entity).toJson()
|
||||||
|
val result = JsonDeserializer(json).toFavouriteCategoryEntity()
|
||||||
|
assertEquals(entity, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package org.koitharu.kotatsu.core.github
|
||||||
|
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.internal.headersContentLength
|
||||||
|
import org.junit.Assert
|
||||||
|
import org.junit.Test
|
||||||
|
import org.koitharu.kotatsu.BuildConfig
|
||||||
|
import org.koitharu.kotatsu.parsers.util.await
|
||||||
|
|
||||||
|
class GithubRepositoryTest {
|
||||||
|
|
||||||
|
private val okHttpClient = OkHttpClient()
|
||||||
|
private val repository = GithubRepository(okHttpClient)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun getLatestVersion() = runTest {
|
||||||
|
val version = repository.getLatestVersion()
|
||||||
|
val versionId = VersionId(version.name)
|
||||||
|
|
||||||
|
val apkHead = okHttpClient.newCall(
|
||||||
|
Request.Builder()
|
||||||
|
.url(version.apkUrl)
|
||||||
|
.head()
|
||||||
|
.build()
|
||||||
|
).await()
|
||||||
|
|
||||||
|
Assert.assertTrue(versionId <= VersionId(BuildConfig.VERSION_NAME))
|
||||||
|
Assert.assertTrue(apkHead.isSuccessful)
|
||||||
|
Assert.assertEquals(version.apkSize, apkHead.headersContentLength())
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue