mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-12-22 20:01:50 +01:00
Update chapter recognition and related tests
Includes 3e07100dc2
Co-authored-by: Saud-97 <Saud-97@users.noreply.github.com>
This commit is contained in:
parent
34ac39e7e5
commit
4a71022a60
10
.github/workflows/build_pull_request.yml
vendored
10
.github/workflows/build_pull_request.yml
vendored
@ -5,6 +5,10 @@ on:
|
|||||||
- '**.md'
|
- '**.md'
|
||||||
- 'app/src/main/res/**/strings.xml'
|
- 'app/src/main/res/**/strings.xml'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
@ -21,7 +25,7 @@ jobs:
|
|||||||
uses: gradle/wrapper-validation-action@v1
|
uses: gradle/wrapper-validation-action@v1
|
||||||
|
|
||||||
- name: Dependency Review
|
- name: Dependency Review
|
||||||
uses: actions/dependency-review-action@v1
|
uses: actions/dependency-review-action@v2
|
||||||
|
|
||||||
- name: Set up JDK 11
|
- name: Set up JDK 11
|
||||||
uses: actions/setup-java@v3
|
uses: actions/setup-java@v3
|
||||||
@ -29,7 +33,7 @@ jobs:
|
|||||||
java-version: 11
|
java-version: 11
|
||||||
distribution: adopt
|
distribution: adopt
|
||||||
|
|
||||||
- name: Build app
|
- name: Build app and run unit tests
|
||||||
uses: gradle/gradle-command-action@v2
|
uses: gradle/gradle-command-action@v2
|
||||||
with:
|
with:
|
||||||
arguments: assembleStandardRelease
|
arguments: assembleStandardRelease testStandardReleaseUnitTest
|
14
.github/workflows/build_push.yml
vendored
14
.github/workflows/build_push.yml
vendored
@ -6,18 +6,16 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- v*
|
- v*
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
name: Build app
|
name: Build app
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Cancel previous runs
|
|
||||||
uses: styfle/cancel-workflow-action@0.9.1
|
|
||||||
with:
|
|
||||||
access_token: ${{ github.token }}
|
|
||||||
all_but_latest: true
|
|
||||||
|
|
||||||
- name: Clone repo
|
- name: Clone repo
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
@ -30,10 +28,10 @@ jobs:
|
|||||||
java-version: 11
|
java-version: 11
|
||||||
distribution: adopt
|
distribution: adopt
|
||||||
|
|
||||||
- name: Build app
|
- name: Build app and run unit tests
|
||||||
uses: gradle/gradle-command-action@v2
|
uses: gradle/gradle-command-action@v2
|
||||||
with:
|
with:
|
||||||
arguments: assembleStandardRelease
|
arguments: assembleStandardRelease testStandardReleaseUnitTest
|
||||||
|
|
||||||
# Sign APK and create release for tags
|
# Sign APK and create release for tags
|
||||||
|
|
||||||
|
16
.github/workflows/cancel_pull_request.yml
vendored
16
.github/workflows/cancel_pull_request.yml
vendored
@ -1,16 +0,0 @@
|
|||||||
name: Cancel old pull request workflows
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_run:
|
|
||||||
workflows: ["PR build check"]
|
|
||||||
types:
|
|
||||||
- requested
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
cancel:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: styfle/cancel-workflow-action@0.9.1
|
|
||||||
with:
|
|
||||||
all_but_latest: true
|
|
||||||
workflow_id: ${{ github.event.workflow.id }}
|
|
@ -1,3 +1,4 @@
|
|||||||
|
import org.gradle.api.tasks.testing.logging.TestLogEvent
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
@ -242,16 +243,19 @@ dependencies {
|
|||||||
|
|
||||||
// Tests
|
// Tests
|
||||||
testImplementation(libs.junit)
|
testImplementation(libs.junit)
|
||||||
testImplementation(libs.assertj.core)
|
|
||||||
testImplementation(libs.mockito.core)
|
|
||||||
|
|
||||||
testImplementation(libs.bundles.robolectric)
|
|
||||||
|
|
||||||
// For detecting memory leaks; see https://square.github.io/leakcanary/
|
// For detecting memory leaks; see https://square.github.io/leakcanary/
|
||||||
// debugImplementation(libs.leakcanary.android)
|
// debugImplementation(libs.leakcanary.android)
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
|
withType<Test> {
|
||||||
|
useJUnitPlatform()
|
||||||
|
testLogging {
|
||||||
|
events(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers)
|
// See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers)
|
||||||
withType<KotlinCompile> {
|
withType<KotlinCompile> {
|
||||||
kotlinOptions.freeCompilerArgs += listOf(
|
kotlinOptions.freeCompilerArgs += listOf(
|
||||||
|
@ -46,8 +46,8 @@ object ChapterRecognition {
|
|||||||
// Get chapter title with lower case
|
// Get chapter title with lower case
|
||||||
var name = chapter.name.lowercase()
|
var name = chapter.name.lowercase()
|
||||||
|
|
||||||
// Remove comma's from chapter.
|
// Remove comma's or hyphens.
|
||||||
name = name.replace(',', '.')
|
name = name.replace(',', '.').replace('-', '.')
|
||||||
|
|
||||||
// Remove unwanted white spaces.
|
// Remove unwanted white spaces.
|
||||||
unwantedWhiteSpace.findAll(name).let {
|
unwantedWhiteSpace.findAll(name).let {
|
||||||
|
@ -1,12 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi
|
|
||||||
|
|
||||||
import org.robolectric.RobolectricTestRunner
|
|
||||||
import org.robolectric.annotation.Config
|
|
||||||
import org.robolectric.manifest.AndroidManifest
|
|
||||||
|
|
||||||
class CustomRobolectricGradleTestRunner(klass: Class<*>) : RobolectricTestRunner(klass) {
|
|
||||||
|
|
||||||
override fun getAppManifest(config: Config): AndroidManifest {
|
|
||||||
return super.getAppManifest(config).apply { packageName = "eu.kanade.tachiyomi" }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi
|
|
||||||
|
|
||||||
open class TestApp : App() {
|
|
||||||
|
|
||||||
override fun setupAcra() {
|
|
||||||
// Do nothing
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,377 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.Context
|
|
||||||
import android.os.Build
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
|
||||||
import eu.kanade.tachiyomi.CustomRobolectricGradleTestRunner
|
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.LegacyBackupManager
|
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
|
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
|
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Category
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import kotlinx.serialization.encodeToString
|
|
||||||
import kotlinx.serialization.json.buildJsonObject
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.mockito.Mockito.RETURNS_DEEP_STUBS
|
|
||||||
import org.mockito.Mockito.anyLong
|
|
||||||
import org.mockito.Mockito.mock
|
|
||||||
import org.mockito.Mockito.`when`
|
|
||||||
import org.robolectric.RuntimeEnvironment
|
|
||||||
import org.robolectric.annotation.Config
|
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.InjektModule
|
|
||||||
import uy.kohesive.injekt.api.InjektRegistrar
|
|
||||||
import uy.kohesive.injekt.api.addSingleton
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test class for the [LegacyBackupManager].
|
|
||||||
* Note that this does not include the backup create/restore services.
|
|
||||||
*/
|
|
||||||
@Config(constants = BuildConfig::class, sdk = [Build.VERSION_CODES.M])
|
|
||||||
@RunWith(CustomRobolectricGradleTestRunner::class)
|
|
||||||
class BackupTest {
|
|
||||||
// Create root object
|
|
||||||
var root = Backup()
|
|
||||||
|
|
||||||
// Create information object
|
|
||||||
var information = buildJsonObject {}
|
|
||||||
|
|
||||||
lateinit var app: Application
|
|
||||||
lateinit var context: Context
|
|
||||||
lateinit var source: HttpSource
|
|
||||||
|
|
||||||
lateinit var legacyBackupManager: LegacyBackupManager
|
|
||||||
|
|
||||||
lateinit var db: DatabaseHelper
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setup() {
|
|
||||||
app = RuntimeEnvironment.application
|
|
||||||
context = app.applicationContext
|
|
||||||
legacyBackupManager = LegacyBackupManager(context, 2)
|
|
||||||
db = legacyBackupManager.databaseHelper
|
|
||||||
|
|
||||||
// Mock the source manager
|
|
||||||
val module = object : InjektModule {
|
|
||||||
override fun InjektRegistrar.registerInjectables() {
|
|
||||||
addSingleton(mock(SourceManager::class.java, RETURNS_DEEP_STUBS))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Injekt.importModule(module)
|
|
||||||
|
|
||||||
source = mock(HttpSource::class.java)
|
|
||||||
`when`(legacyBackupManager.sourceManager.get(anyLong())).thenReturn(source)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test that checks if no crashes when no categories in library.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun testRestoreEmptyCategory() {
|
|
||||||
// Restore Json
|
|
||||||
legacyBackupManager.restoreCategories(root.categories ?: emptyList())
|
|
||||||
|
|
||||||
// Check if empty
|
|
||||||
val dbCats = db.getCategories().executeAsBlocking()
|
|
||||||
assertThat(dbCats).isEmpty()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test to check if single category gets restored
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun testRestoreSingleCategory() {
|
|
||||||
// Create category and add to json
|
|
||||||
val category = addSingleCategory("category")
|
|
||||||
|
|
||||||
// Restore Json
|
|
||||||
legacyBackupManager.restoreCategories(root.categories ?: emptyList())
|
|
||||||
|
|
||||||
// Check if successful
|
|
||||||
val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking()
|
|
||||||
assertThat(dbCats).hasSize(1)
|
|
||||||
assertThat(dbCats[0].name).isEqualTo(category.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test to check if multiple categories get restored.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun testRestoreMultipleCategories() {
|
|
||||||
// Create category and add to json
|
|
||||||
val category = addSingleCategory("category")
|
|
||||||
val category2 = addSingleCategory("category2")
|
|
||||||
val category3 = addSingleCategory("category3")
|
|
||||||
val category4 = addSingleCategory("category4")
|
|
||||||
val category5 = addSingleCategory("category5")
|
|
||||||
|
|
||||||
// Insert category to test if no duplicates on restore.
|
|
||||||
db.insertCategory(category).executeAsBlocking()
|
|
||||||
|
|
||||||
// Restore Json
|
|
||||||
legacyBackupManager.restoreCategories(root.categories ?: emptyList())
|
|
||||||
|
|
||||||
// Check if successful
|
|
||||||
val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking()
|
|
||||||
assertThat(dbCats).hasSize(5)
|
|
||||||
assertThat(dbCats[0].name).isEqualTo(category.name)
|
|
||||||
assertThat(dbCats[1].name).isEqualTo(category2.name)
|
|
||||||
assertThat(dbCats[2].name).isEqualTo(category3.name)
|
|
||||||
assertThat(dbCats[3].name).isEqualTo(category4.name)
|
|
||||||
assertThat(dbCats[4].name).isEqualTo(category5.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if restore of manga is successful
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun testRestoreManga() {
|
|
||||||
// Add manga to database
|
|
||||||
val manga = getSingleManga("One Piece")
|
|
||||||
manga.readingModeType = ReadingModeType.VERTICAL.flagValue
|
|
||||||
manga.orientationType = OrientationType.PORTRAIT.flagValue
|
|
||||||
manga.id = db.insertManga(manga).executeAsBlocking().insertedId()
|
|
||||||
|
|
||||||
var favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking()
|
|
||||||
assertThat(favoriteManga).hasSize(1)
|
|
||||||
assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue)
|
|
||||||
assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue)
|
|
||||||
|
|
||||||
// Change manga in database to default values
|
|
||||||
val dbManga = getSingleManga("One Piece")
|
|
||||||
dbManga.id = manga.id
|
|
||||||
db.insertManga(dbManga).executeAsBlocking()
|
|
||||||
|
|
||||||
favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking()
|
|
||||||
assertThat(favoriteManga).hasSize(1)
|
|
||||||
assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.DEFAULT.flagValue)
|
|
||||||
assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.DEFAULT.flagValue)
|
|
||||||
|
|
||||||
// Restore local manga
|
|
||||||
legacyBackupManager.restoreMangaNoFetch(manga, dbManga)
|
|
||||||
|
|
||||||
// Test if restore successful
|
|
||||||
favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking()
|
|
||||||
assertThat(favoriteManga).hasSize(1)
|
|
||||||
assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue)
|
|
||||||
assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue)
|
|
||||||
|
|
||||||
// Clear database to test manga fetch
|
|
||||||
clearDatabase()
|
|
||||||
|
|
||||||
// Test if successful
|
|
||||||
favoriteManga = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking()
|
|
||||||
assertThat(favoriteManga).hasSize(0)
|
|
||||||
|
|
||||||
// Restore Json
|
|
||||||
// Create JSON from manga to test parser
|
|
||||||
val json = legacyBackupManager.parser.encodeToString(manga)
|
|
||||||
// Restore JSON from manga to test parser
|
|
||||||
val jsonManga = legacyBackupManager.parser.decodeFromString<Manga>(json)
|
|
||||||
|
|
||||||
// Restore manga with fetch observable
|
|
||||||
val networkManga = getSingleManga("One Piece")
|
|
||||||
networkManga.description = "This is a description"
|
|
||||||
`when`(source.fetchMangaDetails(jsonManga)).thenReturn(Observable.just(networkManga))
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
legacyBackupManager.fetchManga(source, jsonManga)
|
|
||||||
|
|
||||||
// Check if restore successful
|
|
||||||
val dbCats = legacyBackupManager.databaseHelper.getFavoriteMangas().executeAsBlocking()
|
|
||||||
assertThat(dbCats).hasSize(1)
|
|
||||||
assertThat(dbCats[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue)
|
|
||||||
assertThat(dbCats[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue)
|
|
||||||
assertThat(dbCats[0].description).isEqualTo("This is a description")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test if chapter restore is successful
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun testRestoreChapters() {
|
|
||||||
// Insert manga
|
|
||||||
val manga = getSingleManga("One Piece")
|
|
||||||
manga.id = legacyBackupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId()
|
|
||||||
|
|
||||||
// Create restore list
|
|
||||||
val chapters = mutableListOf<Chapter>()
|
|
||||||
for (i in 1..8) {
|
|
||||||
val chapter = getSingleChapter("Chapter $i")
|
|
||||||
chapter.read = true
|
|
||||||
chapters.add(chapter)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check parser
|
|
||||||
val chaptersJson = legacyBackupManager.parser.encodeToString(chapters)
|
|
||||||
val restoredChapters = legacyBackupManager.parser.decodeFromString<List<Chapter>>(chaptersJson)
|
|
||||||
|
|
||||||
// Fetch chapters from upstream
|
|
||||||
// Create list
|
|
||||||
val chaptersRemote = mutableListOf<Chapter>()
|
|
||||||
(1..10).mapTo(chaptersRemote) { getSingleChapter("Chapter $it") }
|
|
||||||
`when`(source.fetchChapterList(manga)).thenReturn(Observable.just(chaptersRemote))
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
legacyBackupManager.restoreChapters(source, manga, restoredChapters)
|
|
||||||
|
|
||||||
val dbCats = legacyBackupManager.databaseHelper.getChapters(manga).executeAsBlocking()
|
|
||||||
assertThat(dbCats).hasSize(10)
|
|
||||||
assertThat(dbCats[0].read).isEqualTo(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test to check if history restore works
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun restoreHistoryForManga() {
|
|
||||||
val manga = getSingleManga("One Piece")
|
|
||||||
manga.id = legacyBackupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId()
|
|
||||||
|
|
||||||
// Create chapter
|
|
||||||
val chapter = getSingleChapter("Chapter 1")
|
|
||||||
chapter.manga_id = manga.id
|
|
||||||
chapter.read = true
|
|
||||||
chapter.id = legacyBackupManager.databaseHelper.insertChapter(chapter).executeAsBlocking().insertedId()
|
|
||||||
|
|
||||||
val historyJson = getSingleHistory(chapter)
|
|
||||||
|
|
||||||
val historyList = mutableListOf<DHistory>()
|
|
||||||
historyList.add(historyJson)
|
|
||||||
|
|
||||||
// Check parser
|
|
||||||
val historyListJson = legacyBackupManager.parser.encodeToString(historyList)
|
|
||||||
val history = legacyBackupManager.parser.decodeFromString<List<DHistory>>(historyListJson)
|
|
||||||
|
|
||||||
// Restore categories
|
|
||||||
legacyBackupManager.restoreHistoryForManga(history)
|
|
||||||
|
|
||||||
val historyDB = legacyBackupManager.databaseHelper.getHistoryByMangaId(manga.id!!).executeAsBlocking()
|
|
||||||
assertThat(historyDB).hasSize(1)
|
|
||||||
assertThat(historyDB[0].last_read).isEqualTo(1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test to check if tracking restore works
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun restoreTrackForManga() {
|
|
||||||
// Create mangas
|
|
||||||
val manga = getSingleManga("One Piece")
|
|
||||||
val manga2 = getSingleManga("Bleach")
|
|
||||||
manga.id = legacyBackupManager.databaseHelper.insertManga(manga).executeAsBlocking().insertedId()
|
|
||||||
manga2.id = legacyBackupManager.databaseHelper.insertManga(manga2).executeAsBlocking().insertedId()
|
|
||||||
|
|
||||||
// Create track and add it to database
|
|
||||||
// This tests duplicate errors.
|
|
||||||
val track = getSingleTrack(manga)
|
|
||||||
track.last_chapter_read = 5F
|
|
||||||
legacyBackupManager.databaseHelper.insertTrack(track).executeAsBlocking()
|
|
||||||
var trackDB = legacyBackupManager.databaseHelper.getTracks(manga).executeAsBlocking()
|
|
||||||
assertThat(trackDB).hasSize(1)
|
|
||||||
assertThat(trackDB[0].last_chapter_read).isEqualTo(5)
|
|
||||||
track.last_chapter_read = 7F
|
|
||||||
|
|
||||||
// Create track for different manga to test track not in database
|
|
||||||
val track2 = getSingleTrack(manga2)
|
|
||||||
track2.last_chapter_read = 10F
|
|
||||||
|
|
||||||
// Check parser and restore already in database
|
|
||||||
var trackList = listOf(track)
|
|
||||||
// Check parser
|
|
||||||
var trackListJson = legacyBackupManager.parser.encodeToString(trackList)
|
|
||||||
var trackListRestore = legacyBackupManager.parser.decodeFromString<List<Track>>(trackListJson)
|
|
||||||
legacyBackupManager.restoreTrackForManga(manga, trackListRestore)
|
|
||||||
|
|
||||||
// Assert if restore works.
|
|
||||||
trackDB = legacyBackupManager.databaseHelper.getTracks(manga).executeAsBlocking()
|
|
||||||
assertThat(trackDB).hasSize(1)
|
|
||||||
assertThat(trackDB[0].last_chapter_read).isEqualTo(7)
|
|
||||||
|
|
||||||
// Check parser and restore already in database with lower chapter_read
|
|
||||||
track.last_chapter_read = 5F
|
|
||||||
trackList = listOf(track)
|
|
||||||
legacyBackupManager.restoreTrackForManga(manga, trackList)
|
|
||||||
|
|
||||||
// Assert if restore works.
|
|
||||||
trackDB = legacyBackupManager.databaseHelper.getTracks(manga).executeAsBlocking()
|
|
||||||
assertThat(trackDB).hasSize(1)
|
|
||||||
assertThat(trackDB[0].last_chapter_read).isEqualTo(7)
|
|
||||||
|
|
||||||
// Check parser and restore, track not in database
|
|
||||||
trackList = listOf(track2)
|
|
||||||
|
|
||||||
// Check parser
|
|
||||||
trackListJson = legacyBackupManager.parser.encodeToString(trackList)
|
|
||||||
trackListRestore = legacyBackupManager.parser.decodeFromString<List<Track>>(trackListJson)
|
|
||||||
legacyBackupManager.restoreTrackForManga(manga2, trackListRestore)
|
|
||||||
|
|
||||||
// Assert if restore works.
|
|
||||||
trackDB = legacyBackupManager.databaseHelper.getTracks(manga2).executeAsBlocking()
|
|
||||||
assertThat(trackDB).hasSize(1)
|
|
||||||
assertThat(trackDB[0].last_chapter_read).isEqualTo(10)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearJson() {
|
|
||||||
root = Backup()
|
|
||||||
information = buildJsonObject {}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addSingleCategory(name: String): Category {
|
|
||||||
val category = Category.create(name)
|
|
||||||
root.categories = listOf(category)
|
|
||||||
return category
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun clearDatabase() {
|
|
||||||
db.deleteMangas().executeAsBlocking()
|
|
||||||
db.deleteHistory().executeAsBlocking()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSingleHistory(chapter: Chapter): DHistory {
|
|
||||||
return DHistory(chapter.url, 1000)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSingleTrack(manga: Manga): TrackImpl {
|
|
||||||
val track = TrackImpl()
|
|
||||||
track.title = manga.title
|
|
||||||
track.manga_id = manga.id!!
|
|
||||||
track.sync_id = 1
|
|
||||||
return track
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSingleManga(title: String): MangaImpl {
|
|
||||||
val manga = MangaImpl()
|
|
||||||
manga.source = 1
|
|
||||||
manga.title = title
|
|
||||||
manga.url = "/manga/$title"
|
|
||||||
manga.favorite = true
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSingleChapter(name: String): ChapterImpl {
|
|
||||||
val chapter = ChapterImpl()
|
|
||||||
chapter.name = name
|
|
||||||
chapter.url = "/read-online/$name-page-1.html"
|
|
||||||
return chapter
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.database
|
|
||||||
|
|
||||||
import android.os.Build
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
|
||||||
import eu.kanade.tachiyomi.CustomRobolectricGradleTestRunner
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.robolectric.RuntimeEnvironment
|
|
||||||
import org.robolectric.annotation.Config
|
|
||||||
|
|
||||||
@Config(constants = BuildConfig::class, sdk = [Build.VERSION_CODES.M])
|
|
||||||
@RunWith(CustomRobolectricGradleTestRunner::class)
|
|
||||||
class CategoryTest {
|
|
||||||
|
|
||||||
lateinit var db: DatabaseHelper
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setup() {
|
|
||||||
val app = RuntimeEnvironment.application
|
|
||||||
db = DatabaseHelper(app)
|
|
||||||
|
|
||||||
// Create 5 manga
|
|
||||||
createManga("a")
|
|
||||||
createManga("b")
|
|
||||||
createManga("c")
|
|
||||||
createManga("d")
|
|
||||||
createManga("e")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testHasCategories() {
|
|
||||||
// Create 2 categories
|
|
||||||
createCategory("Reading")
|
|
||||||
createCategory("Hold")
|
|
||||||
|
|
||||||
val categories = db.getCategories().executeAsBlocking()
|
|
||||||
assertThat(categories).hasSize(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testHasLibraryMangas() {
|
|
||||||
val mangas = db.getLibraryMangas().executeAsBlocking()
|
|
||||||
assertThat(mangas).hasSize(5)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testHasCorrectFavorites() {
|
|
||||||
val m = Manga.create(0)
|
|
||||||
m.title = "title"
|
|
||||||
m.author = ""
|
|
||||||
m.artist = ""
|
|
||||||
m.thumbnail_url = ""
|
|
||||||
m.genre = "a list of genres"
|
|
||||||
m.description = "long description"
|
|
||||||
m.url = "url to manga"
|
|
||||||
m.favorite = false
|
|
||||||
db.insertManga(m).executeAsBlocking()
|
|
||||||
val mangas = db.getLibraryMangas().executeAsBlocking()
|
|
||||||
assertThat(mangas).hasSize(5)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testMangaInCategory() {
|
|
||||||
// Create 2 categories
|
|
||||||
createCategory("Reading")
|
|
||||||
createCategory("Hold")
|
|
||||||
|
|
||||||
// It should not have 0 as id
|
|
||||||
val c = db.getCategories().executeAsBlocking()[0]
|
|
||||||
assertThat(c.id).isNotZero
|
|
||||||
|
|
||||||
// Add a manga to a category
|
|
||||||
val m = db.getLibraryMangas().executeAsBlocking()[0]
|
|
||||||
val mc = MangaCategory.create(m, c)
|
|
||||||
db.insertMangaCategory(mc).executeAsBlocking()
|
|
||||||
|
|
||||||
// Get mangas from library and assert manga category is the same
|
|
||||||
val mangas = db.getLibraryMangas().executeAsBlocking()
|
|
||||||
for (manga in mangas) {
|
|
||||||
if (manga.id == m.id) {
|
|
||||||
assertThat(manga.category).isEqualTo(c.id)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createManga(title: String) {
|
|
||||||
val m = Manga.create(0)
|
|
||||||
m.title = title
|
|
||||||
m.author = ""
|
|
||||||
m.artist = ""
|
|
||||||
m.thumbnail_url = ""
|
|
||||||
m.genre = "a list of genres"
|
|
||||||
m.description = "long description"
|
|
||||||
m.url = "url to manga"
|
|
||||||
m.favorite = true
|
|
||||||
db.insertManga(m).executeAsBlocking()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createCategory(name: String) {
|
|
||||||
val c = CategoryImpl()
|
|
||||||
c.name = name
|
|
||||||
db.insertCategory(c).executeAsBlocking()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,497 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.database
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
|
||||||
import eu.kanade.tachiyomi.util.chapter.ChapterRecognition
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
|
|
||||||
class ChapterRecognitionTest {
|
|
||||||
/**
|
|
||||||
* The manga containing manga title
|
|
||||||
*/
|
|
||||||
lateinit var manga: Manga
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The chapter containing chapter name
|
|
||||||
*/
|
|
||||||
lateinit var chapter: Chapter
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set chapter title
|
|
||||||
* @param name name of chapter
|
|
||||||
* @return chapter object
|
|
||||||
*/
|
|
||||||
private fun createChapter(name: String): Chapter {
|
|
||||||
chapter = Chapter.create()
|
|
||||||
chapter.name = name
|
|
||||||
return chapter
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set manga title
|
|
||||||
* @param title title of manga
|
|
||||||
* @return manga object
|
|
||||||
*/
|
|
||||||
private fun createManga(title: String): Manga {
|
|
||||||
manga.title = title
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called before test
|
|
||||||
*/
|
|
||||||
@Before
|
|
||||||
fun setup() {
|
|
||||||
manga = Manga.create(0).apply { title = "random" }
|
|
||||||
chapter = Chapter.create()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ch.xx base case
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun ChCaseBase() {
|
|
||||||
createManga("Mokushiroku Alice")
|
|
||||||
|
|
||||||
createChapter("Mokushiroku Alice Vol.1 Ch.4: Misrepresentation")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(4f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ch. xx base case but space after period
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun ChCaseBase2() {
|
|
||||||
createManga("Mokushiroku Alice")
|
|
||||||
|
|
||||||
createChapter("Mokushiroku Alice Vol. 1 Ch. 4: Misrepresentation")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(4f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ch.xx.x base case
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun ChCaseDecimal() {
|
|
||||||
createManga("Mokushiroku Alice")
|
|
||||||
|
|
||||||
createChapter("Mokushiroku Alice Vol.1 Ch.4.1: Misrepresentation")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(4.1f)
|
|
||||||
|
|
||||||
createChapter("Mokushiroku Alice Vol.1 Ch.4.4: Misrepresentation")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(4.4f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ch.xx.a base case
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun ChCaseAlpha() {
|
|
||||||
createManga("Mokushiroku Alice")
|
|
||||||
|
|
||||||
createChapter("Mokushiroku Alice Vol.1 Ch.4.a: Misrepresentation")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(4.1f)
|
|
||||||
|
|
||||||
createChapter("Mokushiroku Alice Vol.1 Ch.4.b: Misrepresentation")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(4.2f)
|
|
||||||
|
|
||||||
createChapter("Mokushiroku Alice Vol.1 Ch.4.extra: Misrepresentation")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(4.99f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name containing one number base case
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun OneNumberCaseBase() {
|
|
||||||
createManga("Bleach")
|
|
||||||
|
|
||||||
createChapter("Bleach 567 Down With Snowwhite")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(567f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name containing one number and decimal case
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun OneNumberCaseDecimal() {
|
|
||||||
createManga("Bleach")
|
|
||||||
|
|
||||||
createChapter("Bleach 567.1 Down With Snowwhite")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(567.1f)
|
|
||||||
|
|
||||||
createChapter("Bleach 567.4 Down With Snowwhite")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(567.4f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name containing one number and alpha case
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun OneNumberCaseAlpha() {
|
|
||||||
createManga("Bleach")
|
|
||||||
|
|
||||||
createChapter("Bleach 567.a Down With Snowwhite")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(567.1f)
|
|
||||||
|
|
||||||
createChapter("Bleach 567.b Down With Snowwhite")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(567.2f)
|
|
||||||
|
|
||||||
createChapter("Bleach 567.extra Down With Snowwhite")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(567.99f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter containing manga title and number base case
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun MangaTitleCaseBase() {
|
|
||||||
createManga("Solanin")
|
|
||||||
|
|
||||||
createChapter("Solanin 028 Vol. 2")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter containing manga title and number decimal case
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun MangaTitleCaseDecimal() {
|
|
||||||
createManga("Solanin")
|
|
||||||
|
|
||||||
createChapter("Solanin 028.1 Vol. 2")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28.1f)
|
|
||||||
|
|
||||||
createChapter("Solanin 028.4 Vol. 2")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28.4f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter containing manga title and number alpha case
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun MangaTitleCaseAlpha() {
|
|
||||||
createManga("Solanin")
|
|
||||||
|
|
||||||
createChapter("Solanin 028.a Vol. 2")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28.1f)
|
|
||||||
|
|
||||||
createChapter("Solanin 028.b Vol. 2")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28.2f)
|
|
||||||
|
|
||||||
createChapter("Solanin 028.extra Vol. 2")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28.99f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extreme base case
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun ExtremeCaseBase() {
|
|
||||||
createManga("Onepunch-Man")
|
|
||||||
|
|
||||||
createChapter("Onepunch-Man Punch Ver002 028")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extreme base case decimal
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun ExtremeCaseDecimal() {
|
|
||||||
createManga("Onepunch-Man")
|
|
||||||
|
|
||||||
createChapter("Onepunch-Man Punch Ver002 028.1")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28.1f)
|
|
||||||
|
|
||||||
createChapter("Onepunch-Man Punch Ver002 028.4")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28.4f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extreme base case alpha
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun ExtremeCaseAlpha() {
|
|
||||||
createManga("Onepunch-Man")
|
|
||||||
|
|
||||||
createChapter("Onepunch-Man Punch Ver002 028.a")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28.1f)
|
|
||||||
|
|
||||||
createChapter("Onepunch-Man Punch Ver002 028.b")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28.2f)
|
|
||||||
|
|
||||||
createChapter("Onepunch-Man Punch Ver002 028.extra")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(28.99f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter containing .v2
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun dotV2Case() {
|
|
||||||
createChapter("Vol.1 Ch.5v.2: Alones")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(5f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check for case with number in manga title
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun numberInMangaTitleCase() {
|
|
||||||
createManga("Ayame 14")
|
|
||||||
createChapter("Ayame 14 1 - The summer of 14")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(1f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Case with space between ch. x
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun spaceAfterChapterCase() {
|
|
||||||
createManga("Mokushiroku Alice")
|
|
||||||
createChapter("Mokushiroku Alice Vol.1 Ch. 4: Misrepresentation")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(4f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter containing mar(ch)
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun marchInChapterCase() {
|
|
||||||
createManga("Ayame 14")
|
|
||||||
createChapter("Vol.1 Ch.1: March 25 (First Day Cohabiting)")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(1f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter containing range
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun rangeInChapterCase() {
|
|
||||||
createChapter("Ch.191-200 Read Online")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(191f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter containing multiple zeros
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun multipleZerosCase() {
|
|
||||||
createChapter("Vol.001 Ch.003: Kaguya Doesn't Know Much")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(3f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter with version before number
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun chapterBeforeNumberCase() {
|
|
||||||
createManga("Onepunch-Man")
|
|
||||||
createChapter("Onepunch-Man Punch Ver002 086 : Creeping Darkness [3]")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(86f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Case with version attached to chapter number
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun vAttachedToChapterCase() {
|
|
||||||
createManga("Ansatsu Kyoushitsu")
|
|
||||||
createChapter("Ansatsu Kyoushitsu 011v002: Assembly Time")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(11f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Case where the chapter title contains the chapter
|
|
||||||
* But wait it's not actual the chapter number.
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun NumberAfterMangaTitleWithChapterInChapterTitleCase() {
|
|
||||||
createChapter("Tokyo ESP 027: Part 002: Chapter 001")
|
|
||||||
createManga("Tokyo ESP")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(027f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* unParsable chapter
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun unParsableCase() {
|
|
||||||
createChapter("Foo")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(-1f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* chapter with time in title
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun timeChapterCase() {
|
|
||||||
createChapter("Fairy Tail 404: 00:00")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(404f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* chapter with alpha without dot
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun alphaWithoutDotCase() {
|
|
||||||
createChapter("Asu No Yoichi 19a")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(19.1f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter title containing extra and vol
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun chapterContainingExtraCase() {
|
|
||||||
createManga("Fairy Tail")
|
|
||||||
|
|
||||||
createChapter("Fairy Tail 404.extravol002")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(404.99f)
|
|
||||||
|
|
||||||
createChapter("Fairy Tail 404 extravol002")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(404.99f)
|
|
||||||
|
|
||||||
createChapter("Fairy Tail 404.evol002")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(404.5f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter title containing omake (japanese extra) and vol
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun chapterContainingOmakeCase() {
|
|
||||||
createManga("Fairy Tail")
|
|
||||||
|
|
||||||
createChapter("Fairy Tail 404.omakevol002")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(404.98f)
|
|
||||||
|
|
||||||
createChapter("Fairy Tail 404 omakevol002")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(404.98f)
|
|
||||||
|
|
||||||
createChapter("Fairy Tail 404.ovol002")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(404.15f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter title containing special and vol
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun chapterContainingSpecialCase() {
|
|
||||||
createManga("Fairy Tail")
|
|
||||||
|
|
||||||
createChapter("Fairy Tail 404.specialvol002")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(404.97f)
|
|
||||||
|
|
||||||
createChapter("Fairy Tail 404 specialvol002")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(404.97f)
|
|
||||||
|
|
||||||
createChapter("Fairy Tail 404.svol002")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(404.19f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Chapter title containing comma's
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun chapterContainingCommasCase() {
|
|
||||||
createManga("One Piece")
|
|
||||||
|
|
||||||
createChapter("One Piece 300,a")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(300.1f)
|
|
||||||
|
|
||||||
createChapter("One Piece Ch,123,extra")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(123.99f)
|
|
||||||
|
|
||||||
createChapter("One Piece the sunny, goes swimming 024,005")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(24.005f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test for chapters containing season
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun chapterContainingSeasonCase() {
|
|
||||||
createManga("D.I.C.E")
|
|
||||||
|
|
||||||
createChapter("D.I.C.E[Season 001] Ep. 007")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(7f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test for chapters in format sx - chapter xx
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun chapterContainingSeasonCase2() {
|
|
||||||
createManga("The Gamer")
|
|
||||||
|
|
||||||
createChapter("S3 - Chapter 20")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(20f)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test for chapters ending with s
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
fun chaptersEndingWithS() {
|
|
||||||
createManga("One Outs")
|
|
||||||
|
|
||||||
createChapter("One Outs 001")
|
|
||||||
ChapterRecognition.parseChapterNumber(chapter, manga)
|
|
||||||
assertThat(chapter.chapter_number).isEqualTo(1f)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,136 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.library
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Build
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
|
||||||
import eu.kanade.tachiyomi.CustomRobolectricGradleTestRunner
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
|
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Test
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.mockito.Matchers.anyLong
|
|
||||||
import org.mockito.Mockito.RETURNS_DEEP_STUBS
|
|
||||||
import org.mockito.Mockito.mock
|
|
||||||
import org.mockito.Mockito.`when`
|
|
||||||
import org.robolectric.Robolectric
|
|
||||||
import org.robolectric.RuntimeEnvironment
|
|
||||||
import org.robolectric.annotation.Config
|
|
||||||
import rx.Observable
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.InjektModule
|
|
||||||
import uy.kohesive.injekt.api.InjektRegistrar
|
|
||||||
import uy.kohesive.injekt.api.addSingleton
|
|
||||||
|
|
||||||
@Config(constants = BuildConfig::class, sdk = [Build.VERSION_CODES.M])
|
|
||||||
@RunWith(CustomRobolectricGradleTestRunner::class)
|
|
||||||
class LibraryUpdateServiceTest {
|
|
||||||
|
|
||||||
lateinit var app: Application
|
|
||||||
lateinit var context: Context
|
|
||||||
lateinit var service: LibraryUpdateService
|
|
||||||
lateinit var source: HttpSource
|
|
||||||
|
|
||||||
@Before
|
|
||||||
fun setup() {
|
|
||||||
app = RuntimeEnvironment.application
|
|
||||||
context = app.applicationContext
|
|
||||||
|
|
||||||
// Mock the source manager
|
|
||||||
val module = object : InjektModule {
|
|
||||||
override fun InjektRegistrar.registerInjectables() {
|
|
||||||
addSingleton(mock(SourceManager::class.java, RETURNS_DEEP_STUBS))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Injekt.importModule(module)
|
|
||||||
|
|
||||||
service = Robolectric.setupService(LibraryUpdateService::class.java)
|
|
||||||
source = mock(HttpSource::class.java)
|
|
||||||
`when`(service.sourceManager.get(anyLong())).thenReturn(source)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testLifecycle() {
|
|
||||||
// Smoke test
|
|
||||||
Robolectric.buildService(LibraryUpdateService::class.java)
|
|
||||||
.attach()
|
|
||||||
.create()
|
|
||||||
.startCommand(0, 0)
|
|
||||||
.destroy()
|
|
||||||
.get()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testUpdateManga() {
|
|
||||||
val manga = createManga("/manga1")[0]
|
|
||||||
manga.id = 1L
|
|
||||||
service.db.insertManga(manga).executeAsBlocking()
|
|
||||||
|
|
||||||
val sourceChapters = createChapters("/chapter1", "/chapter2")
|
|
||||||
|
|
||||||
`when`(source.fetchChapterList(manga)).thenReturn(Observable.just(sourceChapters))
|
|
||||||
|
|
||||||
runBlocking {
|
|
||||||
service.updateManga(manga)
|
|
||||||
|
|
||||||
assertThat(service.db.getChapters(manga).executeAsBlocking()).hasSize(2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun testContinuesUpdatingWhenAMangaFails() {
|
|
||||||
var favManga = createManga("/manga1", "/manga2", "/manga3")
|
|
||||||
service.db.insertMangas(favManga).executeAsBlocking()
|
|
||||||
favManga = service.db.getLibraryMangas().executeAsBlocking()
|
|
||||||
|
|
||||||
val chapters = createChapters("/chapter1", "/chapter2")
|
|
||||||
val chapters3 = createChapters("/achapter1", "/achapter2")
|
|
||||||
|
|
||||||
// One of the updates will fail
|
|
||||||
`when`(source.fetchChapterList(favManga[0])).thenReturn(Observable.just(chapters))
|
|
||||||
`when`(source.fetchChapterList(favManga[1])).thenReturn(Observable.error(Exception()))
|
|
||||||
`when`(source.fetchChapterList(favManga[2])).thenReturn(Observable.just(chapters3))
|
|
||||||
|
|
||||||
val intent = Intent()
|
|
||||||
val categoryId = intent.getIntExtra(LibraryUpdateService.KEY_CATEGORY, -1)
|
|
||||||
val target = LibraryUpdateService.Target.CHAPTERS
|
|
||||||
runBlocking {
|
|
||||||
service.addMangaToQueue(categoryId, target)
|
|
||||||
service.updateChapterList()
|
|
||||||
|
|
||||||
// There are 3 network attempts and 2 insertions (1 request failed)
|
|
||||||
assertThat(service.db.getChapters(favManga[0]).executeAsBlocking()).hasSize(2)
|
|
||||||
assertThat(service.db.getChapters(favManga[1]).executeAsBlocking()).hasSize(0)
|
|
||||||
assertThat(service.db.getChapters(favManga[2]).executeAsBlocking()).hasSize(2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createChapters(vararg urls: String): List<Chapter> {
|
|
||||||
val list = mutableListOf<Chapter>()
|
|
||||||
for (url in urls) {
|
|
||||||
val c = Chapter.create()
|
|
||||||
c.url = url
|
|
||||||
c.name = url.substring(1)
|
|
||||||
list.add(c)
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createManga(vararg urls: String): List<LibraryManga> {
|
|
||||||
val list = mutableListOf<LibraryManga>()
|
|
||||||
for (url in urls) {
|
|
||||||
val m = LibraryManga()
|
|
||||||
m.url = url
|
|
||||||
m.title = url.substring(1)
|
|
||||||
m.favorite = true
|
|
||||||
list.add(m)
|
|
||||||
}
|
|
||||||
return list
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,275 @@
|
|||||||
|
package eu.kanade.tachiyomi.util.chapter
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.junit.jupiter.api.parallel.Execution
|
||||||
|
import org.junit.jupiter.api.parallel.ExecutionMode
|
||||||
|
|
||||||
|
@Execution(ExecutionMode.CONCURRENT)
|
||||||
|
class ChapterRecognitionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Basic Ch prefix`() {
|
||||||
|
val mangaTitle = "Mokushiroku Alice"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4: Misrepresentation", 4f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Basic Ch prefix with space after period`() {
|
||||||
|
val mangaTitle = "Mokushiroku Alice"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Mokushiroku Alice Vol. 1 Ch. 4: Misrepresentation", 4f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Basic Ch prefix with decimal`() {
|
||||||
|
val mangaTitle = "Mokushiroku Alice"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4.1: Misrepresentation", 4.1f)
|
||||||
|
assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4.4: Misrepresentation", 4.4f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Basic Ch prefix with alpha postfix`() {
|
||||||
|
val mangaTitle = "Mokushiroku Alice"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4.a: Misrepresentation", 4.1f)
|
||||||
|
assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4.b: Misrepresentation", 4.2f)
|
||||||
|
assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch.4.extra: Misrepresentation", 4.99f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Name containing one number`() {
|
||||||
|
val mangaTitle = "Bleach"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Bleach 567 Down With Snowwhite", 567f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Name containing one number and decimal`() {
|
||||||
|
val mangaTitle = "Bleach"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Bleach 567.1 Down With Snowwhite", 567.1f)
|
||||||
|
assertChapter(mangaTitle, "Bleach 567.4 Down With Snowwhite", 567.4f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Name containing one number and alpha`() {
|
||||||
|
val mangaTitle = "Bleach"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Bleach 567.a Down With Snowwhite", 567.1f)
|
||||||
|
assertChapter(mangaTitle, "Bleach 567.b Down With Snowwhite", 567.2f)
|
||||||
|
assertChapter(mangaTitle, "Bleach 567.extra Down With Snowwhite", 567.99f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter containing manga title and number`() {
|
||||||
|
val mangaTitle = "Solanin"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Solanin 028 Vol. 2", 28f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter containing manga title and number decimal`() {
|
||||||
|
val mangaTitle = "Solanin"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Solanin 028.1 Vol. 2", 28.1f)
|
||||||
|
assertChapter(mangaTitle, "Solanin 028.4 Vol. 2", 28.4f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter containing manga title and number alpha`() {
|
||||||
|
val mangaTitle = "Solanin"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Solanin 028.a Vol. 2", 28.1f)
|
||||||
|
assertChapter(mangaTitle, "Solanin 028.b Vol. 2", 28.2f)
|
||||||
|
assertChapter(mangaTitle, "Solanin 028.extra Vol. 2", 28.99f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Extreme case`() {
|
||||||
|
val mangaTitle = "Onepunch-Man"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028", 28f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Extreme case with decimal`() {
|
||||||
|
val mangaTitle = "Onepunch-Man"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028.1", 28.1f)
|
||||||
|
assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028.4", 28.4f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Extreme case with alpha`() {
|
||||||
|
val mangaTitle = "Onepunch-Man"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028.a", 28.1f)
|
||||||
|
assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028.b", 28.2f)
|
||||||
|
assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 028.extra", 28.99f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter containing dot v2`() {
|
||||||
|
val mangaTitle = "random"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Vol.1 Ch.5v.2: Alones", 5f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Number in manga title`() {
|
||||||
|
val mangaTitle = "Ayame 14"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Ayame 14 1 - The summer of 14", 1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Space between ch x`() {
|
||||||
|
val mangaTitle = "Mokushiroku Alice"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Mokushiroku Alice Vol.1 Ch. 4: Misrepresentation", 4f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter title with ch substring`() {
|
||||||
|
val mangaTitle = "Ayame 14"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Vol.1 Ch.1: March 25 (First Day Cohabiting)", 1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter containing multiple zeros`() {
|
||||||
|
val mangaTitle = "random"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Vol.001 Ch.003: Kaguya Doesn't Know Much", 3f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter with version before number`() {
|
||||||
|
val mangaTitle = "Onepunch-Man"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Onepunch-Man Punch Ver002 086 : Creeping Darkness [3]", 86f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Version attached to chapter number`() {
|
||||||
|
val mangaTitle = "Ansatsu Kyoushitsu"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Ansatsu Kyoushitsu 011v002: Assembly Time", 11f)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Case where the chapter title contains the chapter
|
||||||
|
* But wait it's not actual the chapter number.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
fun `Number after manga title with chapter in chapter title case`() {
|
||||||
|
val mangaTitle = "Tokyo ESP"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Tokyo ESP 027: Part 002: Chapter 001", 027f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Unparseable chapter`() {
|
||||||
|
val mangaTitle = "random"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Foo", -1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter with time in title`() {
|
||||||
|
val mangaTitle = "random"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Fairy Tail 404: 00:00", 404f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter with alpha without dot`() {
|
||||||
|
val mangaTitle = "random"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Asu No Yoichi 19a", 19.1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter title containing extra and vol`() {
|
||||||
|
val mangaTitle = "Fairy Tail"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Fairy Tail 404.extravol002", 404.99f)
|
||||||
|
assertChapter(mangaTitle, "Fairy Tail 404 extravol002", 404.99f)
|
||||||
|
assertChapter(mangaTitle, "Fairy Tail 404.evol002", 404.5f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter title containing omake (japanese extra) and vol`() {
|
||||||
|
val mangaTitle = "Fairy Tail"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Fairy Tail 404.omakevol002", 404.98f)
|
||||||
|
assertChapter(mangaTitle, "Fairy Tail 404 omakevol002", 404.98f)
|
||||||
|
assertChapter(mangaTitle, "Fairy Tail 404.ovol002", 404.15f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter title containing special and vol`() {
|
||||||
|
val mangaTitle = "Fairy Tail"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "Fairy Tail 404.specialvol002", 404.97f)
|
||||||
|
assertChapter(mangaTitle, "Fairy Tail 404 specialvol002", 404.97f)
|
||||||
|
assertChapter(mangaTitle, "Fairy Tail 404.svol002", 404.19f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter title containing commas`() {
|
||||||
|
val mangaTitle = "One Piece"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "One Piece 300,a", 300.1f)
|
||||||
|
assertChapter(mangaTitle, "One Piece Ch,123,extra", 123.99f)
|
||||||
|
assertChapter(mangaTitle, "One Piece the sunny, goes swimming 024,005", 24.005f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapter title containing hyphens`() {
|
||||||
|
val mangaTitle = "Solo Leveling"
|
||||||
|
|
||||||
|
assertChapter(mangaTitle, "ch 122-a", 122.1f)
|
||||||
|
assertChapter(mangaTitle, "Solo Leveling Ch.123-extra", 123.99f)
|
||||||
|
assertChapter(mangaTitle, "Solo Leveling, 024-005", 24.005f)
|
||||||
|
assertChapter(mangaTitle, "Ch.191-200 Read Online", 191.200f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapters containing season`() {
|
||||||
|
assertChapter("D.I.C.E", "D.I.C.E[Season 001] Ep. 007", 7f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapters in format sx - chapter xx`() {
|
||||||
|
assertChapter("The Gamer", "S3 - Chapter 20", 20f)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Chapters ending with s`() {
|
||||||
|
assertChapter("One Outs", "One Outs 001", 1f)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertChapter(mangaTitle: String, name: String, expected: Float) {
|
||||||
|
val chapter = createChapter(name)
|
||||||
|
ChapterRecognition.parseChapterNumber(chapter, createManga(mangaTitle))
|
||||||
|
assertEquals(expected, chapter.chapter_number)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createManga(title: String): Manga {
|
||||||
|
val manga = Manga.create(0)
|
||||||
|
manga.title = title
|
||||||
|
return manga
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createChapter(name: String): Chapter {
|
||||||
|
val chapter = Chapter.create()
|
||||||
|
chapter.name = name
|
||||||
|
return chapter
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,6 @@ coil_version = "2.0.0-rc03"
|
|||||||
conductor_version = "3.1.5"
|
conductor_version = "3.1.5"
|
||||||
flowbinding_version = "1.2.0"
|
flowbinding_version = "1.2.0"
|
||||||
shizuku_version = "12.1.0"
|
shizuku_version = "12.1.0"
|
||||||
robolectric_version = "3.1.4"
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2"
|
android-shortcut-gradle = "com.github.zellius:android-shortcut-gradle-plugin:0.1.2"
|
||||||
@ -87,12 +86,7 @@ aboutlibraries-gradle = { module = "com.mikepenz.aboutlibraries.plugin:aboutlibr
|
|||||||
shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku_version" }
|
shizuku-api = { module = "dev.rikka.shizuku:api", version.ref = "shizuku_version" }
|
||||||
shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku_version" }
|
shizuku-provider = { module = "dev.rikka.shizuku:provider", version.ref = "shizuku_version" }
|
||||||
|
|
||||||
junit = "junit:junit:4.13.2"
|
junit = "org.junit.jupiter:junit-jupiter:5.9.0"
|
||||||
assertj-core = "org.assertj:assertj-core:3.16.1"
|
|
||||||
mockito-core = "org.mockito:mockito-core:1.10.19"
|
|
||||||
|
|
||||||
robolectric-core = { module = "org.robolectric:robolectric", version.ref = "robolectric_version" }
|
|
||||||
robolectric-playservices = { module = "org.robolectric:shadows-play-services", version.ref = "robolectric_version" }
|
|
||||||
|
|
||||||
leakcanary-android = "com.squareup.leakcanary:leakcanary-android:2.7"
|
leakcanary-android = "com.squareup.leakcanary:leakcanary-android:2.7"
|
||||||
|
|
||||||
@ -106,7 +100,6 @@ coil = ["coil-core","coil-gif",]
|
|||||||
flowbinding = ["flowbinding-android","flowbinding-appcompat","flowbinding-recyclerview","flowbinding-swiperefreshlayout","flowbinding-viewpager"]
|
flowbinding = ["flowbinding-android","flowbinding-appcompat","flowbinding-recyclerview","flowbinding-swiperefreshlayout","flowbinding-viewpager"]
|
||||||
conductor = ["conductor-core","conductor-viewpager","conductor-support-preference"]
|
conductor = ["conductor-core","conductor-viewpager","conductor-support-preference"]
|
||||||
shizuku = ["shizuku-api","shizuku-provider"]
|
shizuku = ["shizuku-api","shizuku-provider"]
|
||||||
robolectric = ["robolectric-core","robolectric-playservices"]
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
kotlinter = { id = "org.jmailen.kotlinter", version = "3.10.0"}
|
kotlinter = { id = "org.jmailen.kotlinter", version = "3.10.0"}
|
||||||
|
Loading…
Reference in New Issue
Block a user