mirror of
https://github.com/Suwayomi/Suwayomi-Server.git
synced 2026-07-01 09:54:34 -05:00
implement Source Filters
This commit is contained in:
@@ -15,7 +15,7 @@ import suwayomi.tachidesk.manga.model.table.CategoryTable
|
||||
import suwayomi.tachidesk.test.ApplicationTest
|
||||
import suwayomi.tachidesk.test.clearTables
|
||||
|
||||
internal class CategoryControllerTest : ApplicationTest() {
|
||||
class CategoryControllerTest : ApplicationTest() {
|
||||
@Test
|
||||
fun categoryReorder() {
|
||||
Category.createCategory("foo")
|
||||
|
||||
@@ -0,0 +1,323 @@
|
||||
package suwayomi.tachidesk.manga.impl
|
||||
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import io.javalin.plugin.json.JavalinJackson
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.junit.jupiter.api.AfterAll
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import rx.Observable
|
||||
import suwayomi.tachidesk.manga.impl.Search.FilterChange
|
||||
import suwayomi.tachidesk.manga.impl.Search.FilterObject
|
||||
import suwayomi.tachidesk.manga.impl.Search.SerializableGroup
|
||||
import suwayomi.tachidesk.manga.impl.Search.getFilterList
|
||||
import suwayomi.tachidesk.manga.impl.Search.setFilter
|
||||
import suwayomi.tachidesk.manga.impl.Search.sourceSearch
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.registerCatalogueSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.GetCatalogueSource.unregisterCatalogueSource
|
||||
import suwayomi.tachidesk.manga.impl.util.source.StubSource
|
||||
import suwayomi.tachidesk.test.ApplicationTest
|
||||
import suwayomi.tachidesk.test.createSMangas
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.full.primaryConstructor
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
class SearchTest : ApplicationTest() {
|
||||
class FakeSearchableSource(id: Long) : StubSource(id) {
|
||||
var mangas: List<SManga> = emptyList()
|
||||
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
return Observable.just(MangasPage(mangas, false))
|
||||
}
|
||||
}
|
||||
|
||||
private val sourceId = 1L
|
||||
private val source = FakeSearchableSource(sourceId)
|
||||
private val mangasCount = 10
|
||||
|
||||
@BeforeAll
|
||||
fun setup() {
|
||||
registerCatalogueSource(sourceId to source)
|
||||
|
||||
this.source.mangas = createSMangas(mangasCount)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun searchWorks() {
|
||||
val searchResults = runBlocking {
|
||||
sourceSearch(sourceId, "all the mangas", 1)
|
||||
}
|
||||
|
||||
assertEquals(mangasCount, searchResults.mangaList.size, "should return all the mangas")
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
fun teardown() {
|
||||
unregisterCatalogueSource(this.sourceId)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
class FilterListTest : ApplicationTest() {
|
||||
open class EmptyFilterListSource(id: Long) : StubSource(id) {
|
||||
open var mFilterList = FilterList()
|
||||
|
||||
override fun getFilterList(): FilterList {
|
||||
return mFilterList
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `empty FilterList returns empty List`() {
|
||||
val source = registerSource(EmptyFilterListSource::class)
|
||||
source.mFilterList = FilterList()
|
||||
|
||||
val filterList = getFilterList(source.id, false)
|
||||
|
||||
assertEquals(
|
||||
0, filterList.size
|
||||
)
|
||||
}
|
||||
|
||||
class FilterListSource(id: Long) : EmptyFilterListSource(id) {
|
||||
class SelectFilter(name: String, values: Array<String>) : Filter.Select<String>(name, values)
|
||||
class TextFilter(name: String) : Filter.Text(name)
|
||||
class TestCheckBox(name: String) : Filter.CheckBox(name, false)
|
||||
class TriState(name: String, state: Int) : Filter.TriState(name, state)
|
||||
class Group(name: String, state: List<TestCheckBox>) : Filter.Group<TestCheckBox>(name, state)
|
||||
class Sort(name: String, values: Array<String>, state: Selection) : Filter.Sort(name, values, state)
|
||||
|
||||
override var mFilterList = FilterList(
|
||||
Filter.Header("This is a header"),
|
||||
Filter.Separator(),
|
||||
SelectFilter("Select one of these:", arrayOf("this", "that", "none of them")),
|
||||
TextFilter("text filter"),
|
||||
TestCheckBox("check this or else!"),
|
||||
TriState("wanna hook up?", Filter.TriState.STATE_IGNORE),
|
||||
Group(
|
||||
"my Todo",
|
||||
listOf(
|
||||
TestCheckBox("Write Tests"),
|
||||
TestCheckBox("Write More Tests"),
|
||||
TestCheckBox("Write Even More Tests"),
|
||||
)
|
||||
),
|
||||
Sort(
|
||||
"Sort",
|
||||
arrayOf("Alphabetic", "Date published", "Rating"),
|
||||
Filter.Sort.Selection(2, false)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun convertsEveryTypeCorrectly() {
|
||||
val source = registerSource(FilterListSource::class)
|
||||
val filterList = getFilterList(source.id, false)
|
||||
|
||||
assertEquals(
|
||||
FilterObject("Header", source.mFilterList[0]),
|
||||
filterList[0]
|
||||
)
|
||||
assertEquals(
|
||||
FilterObject("Separator", source.mFilterList[1]),
|
||||
filterList[1]
|
||||
)
|
||||
assertEquals(
|
||||
FilterObject("Select", source.mFilterList[2]),
|
||||
filterList[2]
|
||||
)
|
||||
assertEquals(
|
||||
FilterObject("Text", source.mFilterList[3]),
|
||||
filterList[3]
|
||||
)
|
||||
assertEquals(
|
||||
FilterObject("CheckBox", source.mFilterList[4]),
|
||||
filterList[4]
|
||||
)
|
||||
assertEquals(
|
||||
FilterObject("TriState", source.mFilterList[5]),
|
||||
filterList[5]
|
||||
)
|
||||
assertEquals(
|
||||
filterList[6],
|
||||
FilterObject(
|
||||
"Group",
|
||||
SerializableGroup(
|
||||
source.mFilterList[6].name,
|
||||
listOf(
|
||||
FilterObject("CheckBox", (source.mFilterList[6].state as List<Filter<*>>)[0]),
|
||||
FilterObject("CheckBox", (source.mFilterList[6].state as List<Filter<*>>)[1]),
|
||||
FilterObject("CheckBox", (source.mFilterList[6].state as List<Filter<*>>)[2]),
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
assertEquals(
|
||||
FilterObject("Sort", source.mFilterList[7]),
|
||||
filterList[7]
|
||||
)
|
||||
|
||||
// make sure that we can convert this to json
|
||||
JavalinJackson().toJsonString(filterList)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Header and Separator should not change`() {
|
||||
val source = registerSource(FilterListSource::class)
|
||||
|
||||
setFilter(
|
||||
source.id,
|
||||
FilterChange(0, "change!")
|
||||
)
|
||||
|
||||
setFilter(
|
||||
source.id,
|
||||
FilterChange(1, "change!")
|
||||
)
|
||||
|
||||
val filterList = getFilterList(source.id, false)
|
||||
|
||||
assertEquals(
|
||||
filterList[0].filter.state,
|
||||
0
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
filterList[1].filter.state,
|
||||
0
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Select changes are Int`() {
|
||||
val source = registerSource(FilterListSource::class)
|
||||
|
||||
setFilter(
|
||||
source.id,
|
||||
FilterChange(2, "1")
|
||||
)
|
||||
|
||||
val filterList = getFilterList(source.id, false)
|
||||
|
||||
assertEquals(
|
||||
filterList[2].filter.state,
|
||||
1
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Text changes are String`() {
|
||||
val source = registerSource(FilterListSource::class)
|
||||
|
||||
setFilter(
|
||||
source.id,
|
||||
FilterChange(3, "I'm a changed man!")
|
||||
)
|
||||
|
||||
val filterList = getFilterList(source.id, false)
|
||||
|
||||
assertEquals(
|
||||
filterList[3].filter.state,
|
||||
"I'm a changed man!"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CheckBox changes are Boolean`() {
|
||||
val source = registerSource(FilterListSource::class)
|
||||
|
||||
setFilter(
|
||||
source.id,
|
||||
FilterChange(4, "true")
|
||||
)
|
||||
|
||||
val filterList = getFilterList(source.id, false)
|
||||
|
||||
assertEquals(
|
||||
filterList[4].filter.state,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `TriState changes are Int`() {
|
||||
val source = registerSource(FilterListSource::class)
|
||||
|
||||
setFilter(
|
||||
source.id,
|
||||
FilterChange(5, "1")
|
||||
)
|
||||
|
||||
val filterList = getFilterList(source.id, false)
|
||||
|
||||
assertEquals(
|
||||
filterList[5].filter.state,
|
||||
Filter.TriState.STATE_INCLUDE
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Group changes are Filters`() {
|
||||
val source = registerSource(FilterListSource::class)
|
||||
|
||||
setFilter(
|
||||
source.id,
|
||||
FilterChange(6, """{"position":0,"state":"true"}""")
|
||||
)
|
||||
|
||||
val filterList = getFilterList(source.id, false)
|
||||
|
||||
assertEquals(
|
||||
(filterList[6].filter.state as List<FilterObject>)[0].filter.state,
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Sort changes are Filter,Sort,Selection`() {
|
||||
val source = registerSource(FilterListSource::class)
|
||||
|
||||
setFilter(
|
||||
source.id,
|
||||
FilterChange(7, """{"index":1,"ascending":"true"}""")
|
||||
)
|
||||
|
||||
val filterList = getFilterList(source.id, false)
|
||||
|
||||
assertEquals(
|
||||
filterList[7].filter.state,
|
||||
Filter.Sort.Selection(1, true)
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private var sourceCount = 0L
|
||||
|
||||
private fun registerSource(sourceClass: KClass<*>): EmptyFilterListSource {
|
||||
return synchronized(sourceCount) {
|
||||
val source = sourceClass.primaryConstructor!!.call(sourceCount) as EmptyFilterListSource
|
||||
registerCatalogueSource(sourceCount to source)
|
||||
sourceCount++
|
||||
source
|
||||
}
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
fun teardown() {
|
||||
(0 until sourceCount).forEach { unregisterCatalogueSource(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package suwayomi.tachidesk
|
||||
package suwayomi.tachidesk.test
|
||||
|
||||
/*
|
||||
* Copyright (C) Contributors to the Suwayomi project
|
||||
@@ -9,7 +9,8 @@ package suwayomi.tachidesk
|
||||
|
||||
import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.source.local.LocalSource
|
||||
import masstest.BASE_PATH
|
||||
import io.javalin.plugin.json.JavalinJackson
|
||||
import io.javalin.plugin.json.JsonMapper
|
||||
import mu.KotlinLogging
|
||||
import org.jetbrains.exposed.sql.Database
|
||||
import org.junit.jupiter.api.BeforeAll
|
||||
@@ -59,6 +60,7 @@ open class ApplicationTest {
|
||||
DI.global.addImport(
|
||||
DI.Module("Server") {
|
||||
bind<ApplicationDirs>() with singleton { applicationDirs }
|
||||
bind<JsonMapper>() with singleton { JavalinJackson() }
|
||||
}
|
||||
)
|
||||
|
||||
@@ -8,6 +8,7 @@ package suwayomi.tachidesk.test
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import ch.qos.logback.classic.Level
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import mu.KotlinLogging
|
||||
import org.jetbrains.exposed.dao.id.IdTable
|
||||
import org.jetbrains.exposed.sql.batchInsert
|
||||
@@ -41,6 +42,17 @@ fun createLibraryManga(
|
||||
}
|
||||
}
|
||||
|
||||
fun createSMangas(
|
||||
count: Int
|
||||
): List<SManga> {
|
||||
return (0 until count).map {
|
||||
SManga.create().apply {
|
||||
title = "Manga $it"
|
||||
url = "https://$title"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun createChapters(
|
||||
mangaId: Int,
|
||||
amount: Int,
|
||||
|
||||
Reference in New Issue
Block a user