Manga parsers unit tests

This commit is contained in:
Koitharu
2020-03-15 15:19:32 +02:00
parent c765e03b28
commit f0b3400103
10 changed files with 157 additions and 254 deletions

View File

@@ -4,14 +4,26 @@ import android.content.Context
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaSource
class SourceConfig(context: Context, source: MangaSource) {
interface SourceConfig {
private val prefs = context.getSharedPreferences(source.name, Context.MODE_PRIVATE)
fun getDomain(defaultValue: String): String
private val keyDomain = context.getString(R.string.key_parser_domain)
private class PrefSourceConfig(context: Context, source: MangaSource) : SourceConfig {
fun getDomain(defaultValue: String) = prefs.getString(keyDomain, defaultValue)
?.takeUnless(String::isBlank)
?: defaultValue
private val prefs = context.getSharedPreferences(source.name, Context.MODE_PRIVATE)
private val keyDomain = context.getString(R.string.key_parser_domain)
override fun getDomain(defaultValue: String) = prefs.getString(keyDomain, defaultValue)
?.takeUnless(String::isBlank)
?: defaultValue
}
companion object {
@JvmStatic
operator fun invoke(context: Context, source: MangaSource): SourceConfig =
PrefSourceConfig(context, source)
}
}

View File

@@ -11,7 +11,7 @@ import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.prefs.SourceConfig
import org.koitharu.kotatsu.utils.ext.await
class MangaLoaderContext : KoinComponent {
open class MangaLoaderContext : KoinComponent {
private val okHttp by inject<OkHttpClient>()
@@ -43,5 +43,5 @@ class MangaLoaderContext : KoinComponent {
return okHttp.newCall(request.build()).await()
}
fun getSettings(source: MangaSource) = SourceConfig(get(), source)
open fun getSettings(source: MangaSource) = SourceConfig(get(), source)
}

View File

@@ -0,0 +1,114 @@
package org.koitharu.kotatsu.parsers
import kotlinx.coroutines.runBlocking
import okhttp3.OkHttpClient
import org.junit.Assert
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.koin.core.context.startKoin
import org.koin.dsl.module
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.prefs.SourceConfig
import org.koitharu.kotatsu.domain.MangaLoaderContext
import org.koitharu.kotatsu.domain.MangaProviderFactory
import org.koitharu.kotatsu.utils.AssertX
import java.util.concurrent.TimeUnit
@RunWith(Parameterized::class)
class RemoteRepositoryTest(source: MangaSource) {
private val repo = MangaProviderFactory.create(source)
@Test
fun getList() {
val list = runBlocking { repo.getList(60) }
Assert.assertFalse(list.isEmpty())
val item = list.random()
AssertX.assertContentType(item.coverUrl, "image")
AssertX.assertContentType(item.url, "text", "html")
Assert.assertFalse(item.title.isBlank())
}
@Test
fun search() {
val list = runBlocking { repo.getList(0, query = "tail") }
Assert.assertFalse(list.isEmpty())
val item = list.random()
AssertX.assertContentType(item.coverUrl, "image")
AssertX.assertContentType(item.url, "text", "html")
Assert.assertFalse(item.title.isBlank())
}
@Test
fun getTags() {
val tags = runBlocking { repo.getTags() }
Assert.assertFalse(tags.isEmpty())
val tag = tags.random()
Assert.assertFalse(tag.key.isBlank())
Assert.assertFalse(tag.title.isBlank())
val list = runBlocking { repo.getList(0, tag = tag) }
Assert.assertFalse(list.isEmpty())
val item = list.random()
AssertX.assertContentType(item.coverUrl, "image")
AssertX.assertContentType(item.url, "text", "html")
Assert.assertFalse(item.title.isBlank())
}
@Test
fun getDetails() {
val manga = runBlocking { repo.getList(0) }.random()
val details = runBlocking { repo.getDetails(manga) }
Assert.assertFalse(details.chapters.isNullOrEmpty())
Assert.assertFalse(details.description.isNullOrEmpty())
val chapter = details.chapters!!.random()
Assert.assertFalse(chapter.name.isBlank())
AssertX.assertContentType(chapter.url, "text", "html")
}
@Test
fun getPages() {
val manga = runBlocking { repo.getList(0) }.random()
val details = runBlocking { repo.getDetails(manga) }
val pages = runBlocking { repo.getPages(details.chapters!!.random()) }
Assert.assertFalse(pages.isEmpty())
val page = pages.random()
val fullUrl = runBlocking { repo.getPageFullUrl(page) }
AssertX.assertContentType(fullUrl, "image")
}
companion object {
@JvmStatic
@BeforeClass
fun initialize() {
startKoin {
modules(listOf(
module {
factory {
OkHttpClient.Builder()
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.build()
}
},
module {
single<MangaLoaderContext> {
object : MangaLoaderContext() {
override fun getSettings(source: MangaSource): SourceConfig {
return SourceConfigMock()
}
}
}
}
))
}
}
@JvmStatic
@Parameterized.Parameters(name = "{0}")
fun getProviders() = (MangaSource.values().toList() - MangaSource.LOCAL).toTypedArray()
}
}

View File

@@ -1,37 +0,0 @@
package org.koitharu.kotatsu.parsers
import kotlinx.coroutines.runBlocking
import okhttp3.OkHttpClient
import org.junit.BeforeClass
import org.koin.core.context.startKoin
import org.koin.dsl.module
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.domain.MangaLoaderContext
abstract class RepositoryTestEnvironment {
lateinit var repository: MangaRepository
@BeforeClass
fun initialize(source: MangaSource) {
startKoin {
module {
factory {
OkHttpClient()
}
single {
MangaLoaderContext()
}
}
}
val constructor = source.cls.getConstructor(MangaLoaderContext::class.java)
repository = constructor.newInstance(MangaLoaderContext())
}
fun getMangaList() = runBlocking { repository.getList(2) }
fun getMangaItem() = runBlocking { repository.getDetails(repository.getList(5).last()) }
fun getTags() = runBlocking { repository.getTags() }
}

View File

@@ -0,0 +1,8 @@
package org.koitharu.kotatsu.parsers
import org.koitharu.kotatsu.core.prefs.SourceConfig
class SourceConfigMock : SourceConfig {
override fun getDomain(defaultValue: String) = defaultValue
}

View File

@@ -1,66 +0,0 @@
package org.koitharu.kotatsu.parsers.repository
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.parsers.MangaParserTest
import org.koitharu.kotatsu.parsers.RepositoryTestEnvironment
import org.koitharu.kotatsu.utils.AssertX
import org.mockito.junit.MockitoJUnitRunner
@RunWith(MockitoJUnitRunner::class)
class MintMangaTest : MangaParserTest {
@Test
override fun testMangaList() {
val list = getMangaList()
Assert.assertTrue(list.size == 70)
val item = list[40]
Assert.assertTrue(item.title.isNotEmpty())
Assert.assertTrue(item.rating in 0f..1f)
AssertX.assertValidUrl(item.url)
AssertX.assertValidUrl(item.coverUrl)
Assert.assertEquals(item.source, MangaSource.MINTMANGA)
}
@Test
override fun testMangaDetails() {
val manga = getMangaItem()
Assert.assertNotNull(manga.largeCoverUrl)
AssertX.assertValidUrl(manga.largeCoverUrl!!)
Assert.assertNotNull(manga.chapters)
val chapter = manga.chapters!!.last()
Assert.assertEquals(chapter.source, MangaSource.MINTMANGA)
AssertX.assertValidUrl(chapter.url)
}
@Test
override fun testMangaPages() {
val chapter = getMangaItem().chapters!!.first()
val pages = runBlocking { repository.getPages(chapter) }
Assert.assertFalse(pages.isEmpty())
Assert.assertEquals(pages.first().source, MangaSource.MINTMANGA)
AssertX.assertValidUrl(runBlocking { repository.getPageFullUrl(pages.first()) })
AssertX.assertValidUrl(runBlocking { repository.getPageFullUrl(pages.last()) })
}
@Test
override fun testTags() {
val tags = getTags()
Assert.assertFalse(tags.isEmpty())
val tag = tags.first()
Assert.assertFalse(tag.title.isBlank())
Assert.assertEquals(tag.source, MangaSource.MINTMANGA)
AssertX.assertValidUrl("https://mintmanga.live/list/genre/${tag.key}")
}
companion object : RepositoryTestEnvironment() {
@JvmStatic
@BeforeClass
fun setUp() = initialize(MangaSource.MINTMANGA)
}
}

View File

@@ -1,66 +0,0 @@
package org.koitharu.kotatsu.parsers.repository
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.parsers.MangaParserTest
import org.koitharu.kotatsu.parsers.RepositoryTestEnvironment
import org.koitharu.kotatsu.utils.AssertX
import org.mockito.junit.MockitoJUnitRunner
@RunWith(MockitoJUnitRunner::class)
class ReadmangaRuTest : MangaParserTest {
@Test
override fun testMangaList() {
val list = getMangaList()
Assert.assertTrue(list.size == 70)
val item = list[40]
Assert.assertTrue(item.title.isNotEmpty())
Assert.assertTrue(item.rating in 0f..1f)
AssertX.assertValidUrl(item.url)
AssertX.assertValidUrl(item.coverUrl)
Assert.assertEquals(item.source, MangaSource.READMANGA_RU)
}
@Test
override fun testMangaDetails() {
val manga = getMangaItem()
Assert.assertNotNull(manga.largeCoverUrl)
AssertX.assertValidUrl(manga.largeCoverUrl!!)
Assert.assertNotNull(manga.chapters)
val chapter = manga.chapters!!.last()
Assert.assertEquals(chapter.source, MangaSource.READMANGA_RU)
AssertX.assertValidUrl(chapter.url)
}
@Test
override fun testMangaPages() {
val chapter = getMangaItem().chapters!!.first()
val pages = runBlocking { repository.getPages(chapter) }
Assert.assertFalse(pages.isEmpty())
Assert.assertEquals(pages.first().source, MangaSource.READMANGA_RU)
AssertX.assertValidUrl(runBlocking { repository.getPageFullUrl(pages.first()) })
AssertX.assertValidUrl(runBlocking { repository.getPageFullUrl(pages.last()) })
}
@Test
override fun testTags() {
val tags = getTags()
Assert.assertFalse(tags.isEmpty())
val tag = tags.first()
Assert.assertFalse(tag.title.isBlank())
Assert.assertEquals(tag.source, MangaSource.READMANGA_RU)
AssertX.assertValidUrl("https://readmanga.me/list/genre/${tag.key}")
}
companion object : RepositoryTestEnvironment() {
@JvmStatic
@BeforeClass
fun setUp() = initialize(MangaSource.READMANGA_RU)
}
}

View File

@@ -1,66 +0,0 @@
package org.koitharu.kotatsu.parsers.repository
import kotlinx.coroutines.runBlocking
import org.junit.Assert
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.parsers.MangaParserTest
import org.koitharu.kotatsu.parsers.RepositoryTestEnvironment
import org.koitharu.kotatsu.utils.AssertX
import org.mockito.junit.MockitoJUnitRunner
@RunWith(MockitoJUnitRunner::class)
class SelfMangaTest : MangaParserTest {
@Test
override fun testMangaList() {
val list = getMangaList()
Assert.assertTrue(list.size == 70)
val item = list[40]
Assert.assertTrue(item.title.isNotEmpty())
Assert.assertTrue(item.rating in 0f..1f)
AssertX.assertValidUrl(item.url)
AssertX.assertValidUrl(item.coverUrl)
Assert.assertEquals(item.source, MangaSource.SELFMANGA)
}
@Test
override fun testMangaDetails() {
val manga = getMangaItem()
Assert.assertNotNull(manga.largeCoverUrl)
AssertX.assertValidUrl(manga.largeCoverUrl!!)
Assert.assertNotNull(manga.chapters)
val chapter = manga.chapters!!.last()
Assert.assertEquals(chapter.source, MangaSource.SELFMANGA)
AssertX.assertValidUrl(chapter.url)
}
@Test
override fun testMangaPages() {
val chapter = getMangaItem().chapters!!.first()
val pages = runBlocking { repository.getPages(chapter) }
Assert.assertFalse(pages.isEmpty())
Assert.assertEquals(pages.first().source, MangaSource.SELFMANGA)
AssertX.assertValidUrl(runBlocking { repository.getPageFullUrl(pages.first()) })
AssertX.assertValidUrl(runBlocking { repository.getPageFullUrl(pages.last()) })
}
@Test
override fun testTags() {
val tags = getTags()
Assert.assertFalse(tags.isEmpty())
val tag = tags.first()
Assert.assertFalse(tag.title.isBlank())
Assert.assertEquals(tag.source, MangaSource.SELFMANGA)
AssertX.assertValidUrl("https://selfmanga.ru/list/genre/${tag.key}")
}
companion object : RepositoryTestEnvironment() {
@JvmStatic
@BeforeClass
fun setUp() = initialize(MangaSource.SELFMANGA)
}
}

View File

@@ -6,17 +6,23 @@ import java.net.URL
object AssertX {
private val VALID_RESPONSE_CODES = arrayOf(
HttpURLConnection.HTTP_OK,
HttpURLConnection.HTTP_MOVED_PERM,
HttpURLConnection.HTTP_MOVED_TEMP
)
fun assertValidUrl(url: String) {
fun assertContentType(url: String, type: String, subtype: String? = null) {
Assert.assertFalse("URL is empty", url.isEmpty())
val cn = URL(url).openConnection() as HttpURLConnection
cn.requestMethod = "HEAD"
cn.connect()
val code = cn.responseCode
Assert.assertTrue("Invalid response code $code", code in VALID_RESPONSE_CODES)
when (val code = cn.responseCode) {
HttpURLConnection.HTTP_MOVED_PERM,
HttpURLConnection.HTTP_MOVED_TEMP -> assertContentType(cn.getHeaderField("Location"), type, subtype)
HttpURLConnection.HTTP_OK -> {
val ct = cn.contentType.substringBeforeLast(';').split("/")
Assert.assertEquals(type, ct.first())
if (subtype != null) {
Assert.assertEquals(subtype, ct.last())
}
}
else -> Assert.fail("Invalid response code $code")
}
}
}