mirror of
				https://github.com/recloudstream/cloudstream.git
				synced 2024-08-15 01:53:11 +00:00 
			
		
		
		
	tests for all providers
This commit is contained in:
		
							parent
							
								
									255265eed2
								
							
						
					
					
						commit
						509a0a6b90
					
				
					 4 changed files with 206 additions and 20 deletions
				
			
		|  | @ -17,8 +17,7 @@ class KawaiifuProvider : MainAPI() { | |||
|         get() = false | ||||
|     override val hasMainPage: Boolean | ||||
|         get() = true | ||||
|      | ||||
|      | ||||
| 
 | ||||
|     override val supportedTypes: Set<TvType> | ||||
|         get() = setOf(TvType.Anime, TvType.AnimeMovie, TvType.ONA) | ||||
| 
 | ||||
|  | @ -26,12 +25,12 @@ class KawaiifuProvider : MainAPI() { | |||
|     override fun getMainPage(): HomePageResponse { | ||||
|         val items = ArrayList<HomePageList>() | ||||
|         val resp = get(mainUrl).text | ||||
|         println("RESP $resp") | ||||
| 
 | ||||
|         val soup = Jsoup.parse(resp) | ||||
| 
 | ||||
|         items.add(HomePageList("Latest Updates", soup.select(".today-update .item").map { | ||||
|          val title = it.selectFirst("img").attr("alt") | ||||
|          AnimeSearchResponse( | ||||
|             val title = it.selectFirst("img").attr("alt") | ||||
|             AnimeSearchResponse( | ||||
|                 title, | ||||
|                 it.selectFirst("a").attr("href"), | ||||
|                 this.name, | ||||
|  | @ -48,8 +47,8 @@ class KawaiifuProvider : MainAPI() { | |||
|             try { | ||||
|                 val title = section.selectFirst(".title").text() | ||||
|                 val anime = section.select(".list-film > .item").map { ani -> | ||||
|                 val animTitle = ani.selectFirst("img").attr("alt") | ||||
|                 AnimeSearchResponse( | ||||
|                     val animTitle = ani.selectFirst("img").attr("alt") | ||||
|                     AnimeSearchResponse( | ||||
|                         animTitle, | ||||
|                         ani.selectFirst("a").attr("href"), | ||||
|                         this.name, | ||||
|  | @ -68,7 +67,7 @@ class KawaiifuProvider : MainAPI() { | |||
|                 e.printStackTrace() | ||||
|             } | ||||
|         } | ||||
|         if(items.size <= 0) throw ErrorLoadingException() | ||||
|         if (items.size <= 0) throw ErrorLoadingException() | ||||
|         return HomePageResponse(items) | ||||
|     } | ||||
| 
 | ||||
|  | @ -151,7 +150,7 @@ class KawaiifuProvider : MainAPI() { | |||
| 
 | ||||
|         val servers = soupa.select(".list-server").map { | ||||
|             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 -> | ||||
|                 if ((if (ep.first.contains("ep=")) ep.first.split("ep=")[1].split("&")[0].toIntOrNull() else null) == episodeNum) { | ||||
|                     ep | ||||
|  | @ -160,27 +159,31 @@ class KawaiifuProvider : MainAPI() { | |||
|             Pair(serverName, episode) | ||||
|         }.map { | ||||
|             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) | ||||
|             } else { | ||||
|                 val html = get(it.second.first).text | ||||
|                 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) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         servers.forEach { | ||||
|             it.second.forEach { source -> | ||||
|                 callback(ExtractorLink( | ||||
|                     "Kawaiifu", | ||||
|                     "${it.first} - ${source.second}", | ||||
|                     source.first, | ||||
|                     "", | ||||
|                     getQualityFromName(source.second), | ||||
|                     source.first.contains(".m3u") | ||||
|                 )) | ||||
|                 callback( | ||||
|                     ExtractorLink( | ||||
|                         "Kawaiifu", | ||||
|                         "${it.first} - ${source.second}", | ||||
|                         source.first, | ||||
|                         "", | ||||
|                         getQualityFromName(source.second), | ||||
|                         source.first.contains(".m3u") | ||||
|                     ) | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|         return true | ||||
|  |  | |||
|  | @ -24,6 +24,8 @@ class WatchCartoonOnlineProvider : MainAPI() { | |||
|         get() = setOf( | ||||
|             TvType.Cartoon, | ||||
|             TvType.Anime, | ||||
|             TvType.AnimeMovie, | ||||
|             TvType.TvSeries | ||||
|         ) | ||||
| 
 | ||||
|     override fun search(query: String): List<SearchResponse> { | ||||
|  | @ -109,7 +111,6 @@ class WatchCartoonOnlineProvider : MainAPI() { | |||
|         val response = get(url).text | ||||
|         val document = Jsoup.parse(response) | ||||
| 
 | ||||
| 
 | ||||
|         return if (!isMovie) { | ||||
|             val title = document.selectFirst("td.vsbaslik > h2").text() | ||||
|             val poster = fixUrl(document.selectFirst("div#cat-img-desc > div > img").attr("src")) | ||||
|  |  | |||
							
								
								
									
										177
									
								
								app/src/test/java/com/lagradost/cloudstream3/ProviderTests.kt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								app/src/test/java/com/lagradost/cloudstream3/ProviderTests.kt
									
										
									
									
									
										Normal 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) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue