tests for all providers

This commit is contained in:
LagradOst 2021-10-03 01:37:12 +02:00
parent 255265eed2
commit 509a0a6b90
4 changed files with 206 additions and 20 deletions

View file

@ -14,6 +14,9 @@ if (allFilesFromDir != null) {
android { android {
testOptions {
unitTests.returnDefaultValues = true
}
signingConfigs { signingConfigs {
prerelease { prerelease {
if (prerelaseStoreFile != null) { if (prerelaseStoreFile != null) {
@ -76,6 +79,8 @@ repositories {
} }
dependencies { dependencies {
testImplementation 'org.json:json:20180813'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.6.0' implementation 'androidx.core:core-ktx:1.6.0'
implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'androidx.appcompat:appcompat:1.3.1'

View file

@ -17,8 +17,7 @@ class KawaiifuProvider : MainAPI() {
get() = false get() = false
override val hasMainPage: Boolean override val hasMainPage: Boolean
get() = true get() = true
override val supportedTypes: Set<TvType> override val supportedTypes: Set<TvType>
get() = setOf(TvType.Anime, TvType.AnimeMovie, TvType.ONA) get() = setOf(TvType.Anime, TvType.AnimeMovie, TvType.ONA)
@ -26,12 +25,12 @@ class KawaiifuProvider : MainAPI() {
override fun getMainPage(): HomePageResponse { override fun getMainPage(): HomePageResponse {
val items = ArrayList<HomePageList>() val items = ArrayList<HomePageList>()
val resp = get(mainUrl).text val resp = get(mainUrl).text
println("RESP $resp")
val soup = Jsoup.parse(resp) val soup = Jsoup.parse(resp)
items.add(HomePageList("Latest Updates", soup.select(".today-update .item").map { items.add(HomePageList("Latest Updates", soup.select(".today-update .item").map {
val title = it.selectFirst("img").attr("alt") val title = it.selectFirst("img").attr("alt")
AnimeSearchResponse( AnimeSearchResponse(
title, title,
it.selectFirst("a").attr("href"), it.selectFirst("a").attr("href"),
this.name, this.name,
@ -48,8 +47,8 @@ class KawaiifuProvider : MainAPI() {
try { try {
val title = section.selectFirst(".title").text() val title = section.selectFirst(".title").text()
val anime = section.select(".list-film > .item").map { ani -> val anime = section.select(".list-film > .item").map { ani ->
val animTitle = ani.selectFirst("img").attr("alt") val animTitle = ani.selectFirst("img").attr("alt")
AnimeSearchResponse( AnimeSearchResponse(
animTitle, animTitle,
ani.selectFirst("a").attr("href"), ani.selectFirst("a").attr("href"),
this.name, this.name,
@ -68,7 +67,7 @@ class KawaiifuProvider : MainAPI() {
e.printStackTrace() e.printStackTrace()
} }
} }
if(items.size <= 0) throw ErrorLoadingException() if (items.size <= 0) throw ErrorLoadingException()
return HomePageResponse(items) return HomePageResponse(items)
} }
@ -151,7 +150,7 @@ class KawaiifuProvider : MainAPI() {
val servers = soupa.select(".list-server").map { val servers = soupa.select(".list-server").map {
val serverName = it.selectFirst(".server-name").text() val serverName = it.selectFirst(".server-name").text()
val episodes = it.select(".list-ep > li > a").map { episode -> Pair(episode.attr("href"), episode.text()) } val episodes = it.select(".list-ep > li > a").map { episode -> Pair(episode.attr("href"), episode.text()) }
val episode = if (episodeNum == null) episodes[0] else episodes.mapNotNull { ep -> val episode = if (episodeNum == null) episodes[0] else episodes.mapNotNull { ep ->
if ((if (ep.first.contains("ep=")) ep.first.split("ep=")[1].split("&")[0].toIntOrNull() else null) == episodeNum) { if ((if (ep.first.contains("ep=")) ep.first.split("ep=")[1].split("&")[0].toIntOrNull() else null) == episodeNum) {
ep ep
@ -160,27 +159,31 @@ class KawaiifuProvider : MainAPI() {
Pair(serverName, episode) Pair(serverName, episode)
}.map { }.map {
if (it.second.first == data) { if (it.second.first == data) {
val sources = soupa.select("video > source").map { source -> Pair(source.attr("src"), source.attr("data-quality")) } val sources = soupa.select("video > source")
.map { source -> Pair(source.attr("src"), source.attr("data-quality")) }
Triple(it.first, sources, it.second.second) Triple(it.first, sources, it.second.second)
} else { } else {
val html = get(it.second.first).text val html = get(it.second.first).text
val soup = Jsoup.parse(html) val soup = Jsoup.parse(html)
val sources = soup.select("video > source").map { source -> Pair(source.attr("src"), source.attr("data-quality")) } val sources = soup.select("video > source")
.map { source -> Pair(source.attr("src"), source.attr("data-quality")) }
Triple(it.first, sources, it.second.second) Triple(it.first, sources, it.second.second)
} }
} }
servers.forEach { servers.forEach {
it.second.forEach { source -> it.second.forEach { source ->
callback(ExtractorLink( callback(
"Kawaiifu", ExtractorLink(
"${it.first} - ${source.second}", "Kawaiifu",
source.first, "${it.first} - ${source.second}",
"", source.first,
getQualityFromName(source.second), "",
source.first.contains(".m3u") getQualityFromName(source.second),
)) source.first.contains(".m3u")
)
)
} }
} }
return true return true

View file

@ -24,6 +24,8 @@ class WatchCartoonOnlineProvider : MainAPI() {
get() = setOf( get() = setOf(
TvType.Cartoon, TvType.Cartoon,
TvType.Anime, TvType.Anime,
TvType.AnimeMovie,
TvType.TvSeries
) )
override fun search(query: String): List<SearchResponse> { override fun search(query: String): List<SearchResponse> {
@ -109,7 +111,6 @@ class WatchCartoonOnlineProvider : MainAPI() {
val response = get(url).text val response = get(url).text
val document = Jsoup.parse(response) val document = Jsoup.parse(response)
return if (!isMovie) { return if (!isMovie) {
val title = document.selectFirst("td.vsbaslik > h2").text() val title = document.selectFirst("td.vsbaslik > h2").text()
val poster = fixUrl(document.selectFirst("div#cat-img-desc > div > img").attr("src")) val poster = fixUrl(document.selectFirst("div#cat-img-desc > div > img").attr("src"))

View file

@ -0,0 +1,177 @@
package com.lagradost.cloudstream3
import com.lagradost.cloudstream3.mvvm.logError
import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.SubtitleHelper
import org.junit.Assert
import org.junit.Test
class ProviderTests {
private fun getAllProviders(): List<MainAPI> {
val allApis = APIHolder.apis
allApis.addAll(APIHolder.restrictedApis)
return allApis
}
@Test
fun providers_exist() {
Assert.assertTrue(getAllProviders().isNotEmpty())
}
@Test
fun provider_correct_data() {
val isoNames = SubtitleHelper.languages.map { it.ISO_639_1 }
Assert.assertFalse("ISO does not contain any languages", isoNames.isNullOrEmpty())
for (api in getAllProviders()) {
Assert.assertTrue("Api does not contain a mainurl", api.mainUrl != "NONE")
Assert.assertTrue("Api does not contain a name", api.name != "NONE")
Assert.assertTrue("Api ${api.name} does not contain a valid language code", isoNames.contains(api.lang))
Assert.assertTrue("Api ${api.name} does not contain any supported types", api.supportedTypes.isNotEmpty())
}
}
@Test
fun provider_correct_homepage() {
for (api in getAllProviders()) {
if (api.hasMainPage) {
try {
val homepage = api.getMainPage()
when {
homepage == null -> {
Assert.fail("Homepage provider ${api.name} did not correctly load homepage!")
}
homepage.items.isEmpty() -> {
Assert.fail("Homepage provider ${api.name} does not contain any items!")
}
homepage.items.any { it.list.isEmpty() } -> {
Assert.fail("Homepage provider ${api.name} does not have any items on result!")
}
}
} catch (e: Exception) {
if (e.cause is NotImplementedError) {
Assert.fail("Provider marked as hasMainPage, while in reality is has not been implemented")
}
logError(e)
}
}
}
}
private fun loadLinks(api: MainAPI, url: String?): Boolean {
Assert.assertNotNull("Api ${api.name} has invalid url on episode", url)
if (url == null) return true
var linksLoaded = 0
try {
val success = api.loadLinks(url, false, {}) { link ->
Assert.assertTrue(
"Api ${api.name} returns link with invalid Quality",
Qualities.values().map { it.value }.contains(link.quality)
)
Assert.assertTrue("Api ${api.name} returns link with invalid url", link.url.length > 4)
linksLoaded++
}
if (success) {
return linksLoaded > 0
}
Assert.assertTrue("Api ${api.name} has returns false on .loadLinks", success)
} catch (e: Exception) {
if (e.cause is NotImplementedError) {
Assert.fail("Provider has not implemented .loadLinks")
}
logError(e)
}
return true
}
@Test
fun provider_correct() {
val searchQueries = listOf("over", "iron", "guy")
val providers = getAllProviders()
for ((index, api) in providers.withIndex()) {
try {
println("Trying $api (${index + 1}/${providers.size})")
var correctResponses = 0
var searchResult: List<SearchResponse>? = null
for (query in searchQueries) {
val response = try {
api.search(query)
} catch (e: Exception) {
if (e.cause is NotImplementedError) {
Assert.fail("Provider has not implemented .search")
}
logError(e)
null
}
if (!response.isNullOrEmpty()) {
correctResponses++
if (searchResult == null) {
searchResult = response
}
}
}
if (correctResponses == 0 || searchResult == null) {
println("Api ${api.name} did not return any valid search responses")
continue
}
try {
var validResults = false
for (result in searchResult) {
Assert.assertEquals("Invalid apiName on response on ${api.name}", result.apiName, api.name)
val load = api.load(result.url) ?: continue
Assert.assertEquals("Invalid apiName on load on ${api.name}", load.apiName, result.apiName)
Assert.assertTrue(
"Api ${api.name} on load does not contain any of the supportedTypes",
api.supportedTypes.contains(load.type)
)
when (load) {
is AnimeLoadResponse -> {
val gotNoEpisodes =
load.dubEpisodes.isNullOrEmpty() && load.subEpisodes.isNullOrEmpty()
if (gotNoEpisodes) {
println("Api ${api.name} got no episodes on ${load.url}")
continue
}
val url = (load.dubEpisodes ?: load.subEpisodes)?.first()?.url
validResults = loadLinks(api, url)
if (!validResults) continue
}
is MovieLoadResponse -> {
val gotNoEpisodes = load.dataUrl.isBlank()
if (gotNoEpisodes) {
println("Api ${api.name} got no movie on ${load.url}")
continue
}
validResults = loadLinks(api, load.dataUrl)
if (!validResults) continue
}
is TvSeriesLoadResponse -> {
val gotNoEpisodes = load.episodes.isEmpty()
if (gotNoEpisodes) {
println("Api ${api.name} got no episodes on ${load.url}")
continue
}
validResults = loadLinks(api, load.episodes.first().data)
if (!validResults) continue
}
}
break
}
Assert.assertTrue("Api ${api.name} did not load on any}", validResults)
} catch (e: Exception) {
if (e.cause is NotImplementedError) {
Assert.fail("Provider has not implemented .load")
}
logError(e)
}
} catch (e: Exception) {
logError(e)
}
}
}
}