Move parsers out of project
This commit is contained in:
@@ -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
|
||||
)
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user