Move parsers out of project

This commit is contained in:
Koitharu
2022-03-15 06:52:33 +02:00
parent 25d52c5a61
commit 02c15f896b
197 changed files with 710 additions and 5374 deletions

View File

@@ -1,27 +0,0 @@
package org.koitharu.kotatsu.core.network
import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.HttpUrl
class TestCookieJar : CookieJar {
private val cache = HashMap<CookieKey, Cookie>()
override fun loadForRequest(url: HttpUrl): List<Cookie> {
val time = System.currentTimeMillis()
return cache.values.filter { it.matches(url) && it.expiresAt >= time }
}
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
cookies.forEach {
val key = CookieKey(url.host, it.name)
cache[key] = it
}
}
private data class CookieKey(
val host: String,
val name: String
)
}

View File

@@ -1,128 +0,0 @@
package org.koitharu.kotatsu.core.parser
import com.google.common.truth.Truth
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.koin.core.component.inject
import org.koin.core.logger.Level
import org.koin.core.parameter.parametersOf
import org.koin.test.KoinTest
import org.koin.test.KoinTestRule
import org.koitharu.kotatsu.core.model.Manga
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.model.SortOrder
import org.koitharu.kotatsu.utils.CoroutineTestRule
import org.koitharu.kotatsu.utils.TestResponse
import org.koitharu.kotatsu.utils.ext.mapToSet
import org.koitharu.kotatsu.utils.ext.medianOrNull
import org.koitharu.kotatsu.utils.isAbsoluteUrl
import org.koitharu.kotatsu.utils.isNotAbsoluteUrl
@RunWith(Parameterized::class)
class RemoteMangaRepositoryTest(private val source: MangaSource) : KoinTest {
private val repo by inject<RemoteMangaRepository> {
parametersOf(source)
}
@get:Rule
val koinTestRule = KoinTestRule.create {
printLogger(Level.ERROR)
modules(repositoryTestModule, parserModule)
}
@get:Rule
val coroutineTestRule = CoroutineTestRule()
@Test
fun list() = coroutineTestRule.runBlockingTest {
val list = repo.getList2(20, query = null, sortOrder = SortOrder.POPULARITY, tags = null)
checkMangaList(list)
}
@Test
fun search() = coroutineTestRule.runBlockingTest {
val subject = repo.getList2(20, query = null, sortOrder = SortOrder.POPULARITY, tags = null)
.first()
val list = repo.getList2(offset = 0, query = subject.title, sortOrder = null, tags = null)
checkMangaList(list)
Truth.assertThat(list.map { it.url }).contains(subject.url)
}
@Test
fun tags() = coroutineTestRule.runBlockingTest {
val tags = repo.getTags()
Truth.assertThat(tags).isNotEmpty()
val keys = tags.map { it.key }
Truth.assertThat(keys).containsNoDuplicates()
Truth.assertThat(keys).doesNotContain("")
val titles = tags.map { it.title }
Truth.assertThat(titles).containsNoDuplicates()
Truth.assertThat(titles).doesNotContain("")
Truth.assertThat(tags.mapToSet { it.source }).containsExactly(source)
val list = repo.getList2(offset = 0, tags = setOf(tags.last()), query = null, sortOrder = null)
checkMangaList(list)
}
@Test
fun details() = coroutineTestRule.runBlockingTest {
val list = repo.getList2(20, query = null, sortOrder = SortOrder.POPULARITY, tags = null)
val manga = list.first()
println(manga.title + ": " + manga.url)
val details = repo.getDetails(manga)
Truth.assertThat(details.chapters).isNotEmpty()
Truth.assertThat(details.publicUrl).isAbsoluteUrl()
Truth.assertThat(details.description).isNotNull()
Truth.assertThat(details.title).startsWith(manga.title)
Truth.assertThat(details.source).isEqualTo(source)
Truth.assertThat(details.chapters?.map { it.id }).containsNoDuplicates()
Truth.assertThat(details.chapters?.map { it.number }).containsNoDuplicates()
Truth.assertThat(details.chapters?.map { it.name }).doesNotContain("")
Truth.assertThat(details.chapters?.mapToSet { it.source }).containsExactly(source)
}
@Test
fun pages() = coroutineTestRule.runBlockingTest {
val list = repo.getList2(20, query = null, sortOrder = SortOrder.POPULARITY, tags = null)
val manga = list.first()
println(manga.title + ": " + manga.url)
val chapter = repo.getDetails(manga).chapters?.firstOrNull() ?: error("Chapter is null")
val pages = repo.getPages(chapter)
Truth.assertThat(pages).isNotEmpty()
Truth.assertThat(pages.map { it.id }).containsNoDuplicates()
Truth.assertThat(pages.mapToSet { it.source }).containsExactly(source)
val page = pages.medianOrNull() ?: error("No page")
val pageUrl = repo.getPageUrl(page)
Truth.assertThat(pageUrl).isNotEmpty()
Truth.assertThat(pageUrl).isAbsoluteUrl()
val pageResponse = TestResponse.testRequest(pageUrl)
Truth.assertThat(pageResponse.code).isIn(200..299)
Truth.assertThat(pageResponse.type).isEqualTo("image")
}
private fun checkMangaList(list: List<Manga>) {
Truth.assertThat(list).isNotEmpty()
Truth.assertThat(list.map { it.id }).containsNoDuplicates()
for (item in list) {
Truth.assertThat(item.url).isNotEmpty()
Truth.assertThat(item.url).isNotAbsoluteUrl()
Truth.assertThat(item.coverUrl).isAbsoluteUrl()
Truth.assertThat(item.title).isNotEmpty()
Truth.assertThat(item.publicUrl).isAbsoluteUrl()
}
}
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{0}")
fun getProviders() = (MangaSource.values().toList() - MangaSource.LOCAL).toTypedArray()
}
}

View File

@@ -1,39 +0,0 @@
package org.koitharu.kotatsu.core.parser
import com.koushikdutta.quack.QuackContext
import okhttp3.CookieJar
import okhttp3.OkHttpClient
import org.koin.dsl.module
import org.koitharu.kotatsu.base.domain.MangaLoaderContext
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.network.TestCookieJar
import org.koitharu.kotatsu.core.network.UserAgentInterceptor
import org.koitharu.kotatsu.core.prefs.SourceSettings
import java.util.concurrent.TimeUnit
val repositoryTestModule
get() = module {
single<CookieJar> { TestCookieJar() }
factory {
OkHttpClient.Builder()
.cookieJar(get())
.addInterceptor(UserAgentInterceptor())
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.build()
}
single<MangaLoaderContext> {
object : MangaLoaderContext(get(), get()) {
override fun getSettings(source: MangaSource): SourceSettings {
return SourceSettingsStub()
}
override suspend fun evaluateJs(script: String): String? {
return QuackContext.create().use {
it.evaluate(script)?.toString()
}
}
}
}
}

View File

@@ -1,10 +0,0 @@
package org.koitharu.kotatsu.core.parser
import org.koitharu.kotatsu.core.prefs.SourceSettings
class SourceSettingsStub : SourceSettings {
override fun getDomain(defaultValue: String) = defaultValue
override fun isUseSsl(defaultValue: Boolean) = defaultValue
}

View File

@@ -1,32 +0,0 @@
package org.koitharu.kotatsu.utils
import okhttp3.OkHttpClient
import okhttp3.Request
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
data class TestResponse(
val code: Int,
val type: String?,
val subtype: String?,
) {
companion object : KoinComponent {
private val okHttp by inject<OkHttpClient>()
fun testRequest(url: String): TestResponse {
val request = Request.Builder()
.url(url)
.head()
.build()
val response = okHttp.newCall(request).execute()
val type = response.body?.contentType()
return TestResponse(
code = response.code,
type = type?.type,
subtype = type?.subtype,
)
}
}
}

View File

@@ -1,13 +0,0 @@
package org.koitharu.kotatsu.utils
import com.google.common.truth.StringSubject
import java.util.regex.Pattern
private val PATTERN_URL_ABSOLUTE = Pattern.compile("https?://[^\\s]+", Pattern.CASE_INSENSITIVE)
private val PATTERN_URL_RELATIVE = Pattern.compile("^/[^\\s]+", Pattern.CASE_INSENSITIVE)
fun StringSubject.isRelativeUrl() = matches(PATTERN_URL_RELATIVE)
fun StringSubject.isAbsoluteUrl() = matches(PATTERN_URL_ABSOLUTE)
fun StringSubject.isNotAbsoluteUrl() = doesNotMatch(PATTERN_URL_ABSOLUTE)