{"src/test/java/com/unspooled/app/data/addon/SystemAddonCatalogTest.kt":["defaultAddonRegistryDelegatesToCatalog:com.unspooled.app.data.addon.SystemAddonCatalogTest","allRequiredSystemAddonsAreSeeded:com.unspooled.app.data.addon.SystemAddonCatalogTest","SystemAddonCatalogTest:com.unspooled.app.data.addon","moreLikeThisDisabledByDefaultRequiresConfiguration:com.unspooled.app.data.addon.SystemAddonCatalogTest","debridEnginesHaveExpectedDefaults:com.unspooled.app.data.addon.SystemAddonCatalogTest","<init>:com.unspooled.app.data.addon.SystemAddonCatalogTest","existingDebridEnginesArePreserved:com.unspooled.app.data.addon.SystemAddonCatalogTest","nativeTmdbIsPrimaryCatalog:com.unspooled.app.data.addon.SystemAddonCatalogTest"],"src/test/java/com/unspooled/app/data/addon/ManifestUpdateManagerTest.kt":["sha256IsStable:com.unspooled.app.data.addon.ManifestUpdateManagerTest","parseStoredManifestRoundTrips:com.unspooled.app.data.addon.ManifestUpdateManagerTest","<init>:com.unspooled.app.data.addon.ManifestUpdateManagerTest","nativeSchemeUrlsSkipFetch:com.unspooled.app.data.addon.ManifestUpdateManagerTest","ManifestUpdateManagerTest:com.unspooled.app.data.addon","isValidManifestRequiresIdNameVersion:com.unspooled.app.data.addon.ManifestUpdateManagerTest"],"src/test/java/com/unspooled/app/data/tmdb/TmdbCatalogWireTest.kt":["TmdbCatalogWireTest:com.unspooled.app.data.tmdb","http401_surfacesAuthError:com.unspooled.app.data.tmdb.TmdbCatalogWireTest","<init>:com.unspooled.app.data.tmdb.TmdbCatalogWireTest","setUp:com.unspooled.app.data.tmdb.TmdbCatalogWireTest","popularMovies_usesBearerAuthAndDeserializesResults:com.unspooled.app.data.tmdb.TmdbCatalogWireTest","tearDown:com.unspooled.app.data.tmdb.TmdbCatalogWireTest"],"src/test/java/com/unspooled/app/data/image/CatalogImageNormalizerTest.kt":["CatalogImageNormalizerTest:com.unspooled.app.data.image","http upgrades to https:com.unspooled.app.data.image.CatalogImageNormalizerTest","non-TMDB URL query params are preserved (signed CDN URLs):com.unspooled.app.data.image.CatalogImageNormalizerTest","existing original URL is resized to w342 for catalog:com.unspooled.app.data.image.CatalogImageNormalizerTest","addon relative poster without slash:com.unspooled.app.data.image.CatalogImageNormalizerTest","full non-TMDB URL passes through unchanged:com.unspooled.app.data.image.CatalogImageNormalizerTest","full URL passthrough with size rewrite for catalog:com.unspooled.app.data.image.CatalogImageNormalizerTest","Kitsu posterImage URL passes through:com.unspooled.app.data.image.CatalogImageNormalizerTest","row backdrop uses w780:com.unspooled.app.data.image.CatalogImageNormalizerTest","<init>:com.unspooled.app.data.image.CatalogImageNormalizerTest","null new poster does not overwrite existing valid poster in normalizeMetaPreview:com.unspooled.app.data.image.CatalogImageNormalizerTest","hero backdrop uses w1280:com.unspooled.app.data.image.CatalogImageNormalizerTest","catalog row receives w342 poster:com.unspooled.app.data.image.CatalogImageNormalizerTest","null and blank return null:com.unspooled.app.data.image.CatalogImageNormalizerTest","query parameters are stripped from normalized URL:com.unspooled.app.data.image.CatalogImageNormalizerTest","TMDB partial path becomes w342 catalog poster:com.unspooled.app.data.image.CatalogImageNormalizerTest","detail poster uses w500:com.unspooled.app.data.image.CatalogImageNormalizerTest","existing w1280 URL is resized to w342 for catalog:com.unspooled.app.data.image.CatalogImageNormalizerTest","addon full poster URL displays if valid:com.unspooled.app.data.image.CatalogImageNormalizerTest"],"src/test/java/com/unspooled/app/data/source/SourceRankerTest.kt":["resolveSortPreset — unknown defaults to RECOMMENDED:com.unspooled.app.data.source.SourceRankerTest","cached reliable source outranks raw 4k source:com.unspooled.app.data.source.SourceRankerTest","speed first with isEpisode = true prefers episode-sized files:com.unspooled.app.data.source.SourceRankerTest","Speed First — uncached sources heavily penalized:com.unspooled.app.data.source.SourceRankerTest","regex REQUIRE — excludes streams that don't match:com.unspooled.app.data.source.SourceRankerTest","regex higher priority rules take precedence:com.unspooled.app.data.source.SourceRankerTest","size score — episode ranges differ from movie ranges:com.unspooled.app.data.source.SourceRankerTest","Recommended — REMUX over 25GB penalized even when cached:com.unspooled.app.data.source.SourceRankerTest","Quality First — uncached 4K REMUX is still penalized:com.unspooled.app.data.source.SourceRankerTest","regex BOOST — boosts matching streams above non-matching:com.unspooled.app.data.source.SourceRankerTest","Speed First — REMUX is hard-penalized regardless of cache:com.unspooled.app.data.source.SourceRankerTest","Recommended — DV source is fine on DV-capable device:com.unspooled.app.data.source.SourceRankerTest","Quality First — Dolby Vision on non-DV device is still penalized:com.unspooled.app.data.source.SourceRankerTest","Unsupported AV1 ranks lower than supported H264 in all presets:com.unspooled.app.data.source.SourceRankerTest","Recommended — cached 4K REMUX beats cached 1080p when device-capable:com.unspooled.app.data.source.SourceRankerTest","Recommended — cached 1080p HEVC 5GB beats uncached 4K REMUX 40GB:com.unspooled.app.data.source.SourceRankerTest","cached remux outranks bluray in Quality First:com.unspooled.app.data.source.SourceRankerTest","SourceRankerTest:com.unspooled.app.data.source","Nuvio filters — excluded Dolby Vision pushes DV below HDR10:com.unspooled.app.data.source.SourceRankerTest","low quality camera flags are penalized:com.unspooled.app.data.source.SourceRankerTest","Nuvio filters — preferred release group wins tie:com.unspooled.app.data.source.SourceRankerTest","<init>:com.unspooled.app.data.source.SourceRankerTest","resolveSortPreset — cache_first migrates to SPEED_FIRST:com.unspooled.app.data.source.SourceRankerTest","regex invalid pattern is silently skipped:com.unspooled.app.data.source.SourceRankerTest","Recommended — Dolby Vision-only source penalized on non-DV device:com.unspooled.app.data.source.SourceRankerTest","recent failure lowers rank and recent success restores confidence:com.unspooled.app.data.source.SourceRankerTest","Speed First — H264 preferred over HEVC on weak devices:com.unspooled.app.data.source.SourceRankerTest","Nuvio filters — max size cap beats huge remux:com.unspooled.app.data.source.SourceRankerTest","remux loses to bluray in Recommended when both uncached:com.unspooled.app.data.source.SourceRankerTest","regex combined BOOST and PENALIZE — net score determines rank:com.unspooled.app.data.source.SourceRankerTest","release quality tags improve ranking and labels:com.unspooled.app.data.source.SourceRankerTest","Quality First — Dolby Vision on DV device gets boosted:com.unspooled.app.data.source.SourceRankerTest","regex EXCLUDE — removes streams that match:com.unspooled.app.data.source.SourceRankerTest","resolveSortPreset — balanced migrates to RECOMMENDED:com.unspooled.app.data.source.SourceRankerTest","Quality First — cached 4K REMUX wins over cached 1080p:com.unspooled.app.data.source.SourceRankerTest","Recommended — 4K is penalized when uncached (bad default experience):com.unspooled.app.data.source.SourceRankerTest","Speed First — 4K is severely penalized:com.unspooled.app.data.source.SourceRankerTest","resolveSortPreset — quality_first stays QUALITY_FIRST:com.unspooled.app.data.source.SourceRankerTest","resolveSortPreset — new values map correctly:com.unspooled.app.data.source.SourceRankerTest","Unsupported DV-only source not preferred in any preset:com.unspooled.app.data.source.SourceRankerTest","regex PENALIZE — demotes matching streams below non-matching:com.unspooled.app.data.source.SourceRankerTest","empty regexRules — no effect on ranking:com.unspooled.app.data.source.SourceRankerTest","Speed First — cached 720p small file beats uncached 4K:com.unspooled.app.data.source.SourceRankerTest"],"src/test/java/com/unspooled/app/data/source/StreamDeduplicatorTest.kt":["geometricRound — zero and negative return zero:com.unspooled.app.data.source.StreamDeduplicatorTest","smartDetect — streams without size are not affected:com.unspooled.app.data.source.StreamDeduplicatorTest","normalizeFilename — handles dots and spaces:com.unspooled.app.data.source.StreamDeduplicatorTest","StreamDeduplicatorTest:com.unspooled.app.data.source","smartDetect — DV and SDR at same size are NOT merged:com.unspooled.app.data.source.StreamDeduplicatorTest","smartDetect — AV1 and H264 at same size are NOT merged:com.unspooled.app.data.source.StreamDeduplicatorTest","smartDetect — same file from different addons IS merged:com.unspooled.app.data.source.StreamDeduplicatorTest","geometricRound — same value always returns same bucket:com.unspooled.app.data.source.StreamDeduplicatorTest","geometricRound — significantly different sizes land in different buckets:com.unspooled.app.data.source.StreamDeduplicatorTest","smartDetect — different release groups at same size are NOT merged:com.unspooled.app.data.source.StreamDeduplicatorTest","geometricRound — identical sizes always same bucket:com.unspooled.app.data.source.StreamDeduplicatorTest","smartDetect — same file with slightly different sizes IS merged:com.unspooled.app.data.source.StreamDeduplicatorTest","geometricRound — small files round correctly:com.unspooled.app.data.source.StreamDeduplicatorTest","normalizeFilename — strips extension and special chars:com.unspooled.app.data.source.StreamDeduplicatorTest","<init>:com.unspooled.app.data.source.StreamDeduplicatorTest"],"src/test/java/com/unspooled/app/data/source/FallbackEngineTest.kt":["classifies network errors as retriable:com.unspooled.app.data.source.FallbackEngineTest","FallbackEngineTest:com.unspooled.app.data.source","tries lower resolution debrid before same resolution free source:com.unspooled.app.data.source.FallbackEngineTest","skips codec incompatible sources:com.unspooled.app.data.source.FallbackEngineTest","retries failed stream once before selecting next source:com.unspooled.app.data.source.FallbackEngineTest","exhausts when all sources tried:com.unspooled.app.data.source.FallbackEngineTest","<init>:com.unspooled.app.data.source.FallbackEngineTest","advances after debrid playback url has already failed:com.unspooled.app.data.source.FallbackEngineTest"],"src/test/java/com/unspooled/app/data/provider/ProviderRegistryProvidedSourcesTest.kt":["embed sources are available without debrid connection:com.unspooled.app.data.provider.ProviderRegistryProvidedSourcesTest","embed sources AND debrid scrapers available when debrid connected:com.unspooled.app.data.provider.ProviderRegistryProvidedSourcesTest","<init>:com.unspooled.app.data.provider.ProviderRegistryProvidedSourcesTest","providers list contains NO banned scrapers:com.unspooled.app.data.provider.ProviderRegistryProvidedSourcesTest","ProviderRegistryProvidedSourcesTest:com.unspooled.app.data.provider","embedSourceProvider is registered as alwaysAvailable:com.unspooled.app.data.provider.ProviderRegistryProvidedSourcesTest","setUp:com.unspooled.app.data.provider.ProviderRegistryProvidedSourcesTest","no scraper proxy URLs in any provider config:com.unspooled.app.data.provider.ProviderRegistryProvidedSourcesTest"],"src/test/java/com/unspooled/app/ui/screens/home/HomeCatalogFetchTest.kt":["<init>:com.unspooled.app.ui.screens.home.HomeCatalogFetchTest","HomeCatalogFetchTest:com.unspooled.app.ui.screens.home","tmdbNativeCatalogIds_mustNotUseShortCoroutineTimeout:com.unspooled.app.ui.screens.home.HomeCatalogFetchTest","tmdbCatalogIds_mustUseDirectApiPath:com.unspooled.app.ui.screens.home.HomeCatalogFetchTest"],"src/test/java/com/unspooled/app/domain/playback/StreamValidatorTest.kt":["403 forbidden rejected:com.unspooled.app.domain.playback.StreamValidatorTest","DASH mpd content type accepted:com.unspooled.app.domain.playback.StreamValidatorTest","video mp4 content type accepted:com.unspooled.app.domain.playback.StreamValidatorTest","206 partial content accepted for ranged GET:com.unspooled.app.domain.playback.StreamValidatorTest","404 not found rejected:com.unspooled.app.domain.playback.StreamValidatorTest","m3u8 extension in URL detected as HLS:com.unspooled.app.domain.playback.StreamValidatorTest","setUp:com.unspooled.app.domain.playback.StreamValidatorTest","401 unauthorized rejected:com.unspooled.app.domain.playback.StreamValidatorTest","<init>:com.unspooled.app.domain.playback.StreamValidatorTest","text html content type rejected:com.unspooled.app.domain.playback.StreamValidatorTest","mpd extension in URL detected as DASH:com.unspooled.app.domain.playback.StreamValidatorTest","non-http scheme returns failure:com.unspooled.app.domain.playback.StreamValidatorTest","tearDown:com.unspooled.app.domain.playback.StreamValidatorTest","application json content type rejected:com.unspooled.app.domain.playback.StreamValidatorTest","HLS m3u8 content type accepted:com.unspooled.app.domain.playback.StreamValidatorTest","empty url returns failure:com.unspooled.app.domain.playback.StreamValidatorTest","StreamValidatorTest:com.unspooled.app.domain.playback"],"src/test/java/com/unspooled/app/domain/util/ContentFilterTest.kt":["kids profile — Family passes:com.unspooled.app.domain.util.ContentFilterTest","kids profile — Comedy passes:com.unspooled.app.domain.util.ContentFilterTest","kids profile — Horror is blocked:com.unspooled.app.domain.util.ContentFilterTest","kids profile — War is blocked:com.unspooled.app.domain.util.ContentFilterTest","kids profile — case insensitive match:com.unspooled.app.domain.util.ContentFilterTest","kids profile — Documentary passes:com.unspooled.app.domain.util.ContentFilterTest","kids profile — Action is blocked:com.unspooled.app.domain.util.ContentFilterTest","ContentFilterTest:com.unspooled.app.domain.util","kids profile — all safe genres passes:com.unspooled.app.domain.util.ContentFilterTest","kids profile — Crime is blocked:com.unspooled.app.domain.util.ContentFilterTest","kids profile — Thriller is blocked:com.unspooled.app.domain.util.ContentFilterTest","kids profile — Animation passes:com.unspooled.app.domain.util.ContentFilterTest","<init>:com.unspooled.app.domain.util.ContentFilterTest","kids profile — empty genre list passes:com.unspooled.app.domain.util.ContentFilterTest","kids profile — mixed genres with one mature is blocked:com.unspooled.app.domain.util.ContentFilterTest","kids profile — substring match works for Sci-Fi Horror:com.unspooled.app.domain.util.ContentFilterTest","kids profile — item with no genres passes (can't filter without data):com.unspooled.app.domain.util.ContentFilterTest","standard profile — all content is appropriate:com.unspooled.app.domain.util.ContentFilterTest","kids profile — Mystery is blocked:com.unspooled.app.domain.util.ContentFilterTest"],"src/test/java/com/unspooled/app/domain/model/CatalogRowPaginationTest.kt":["mergeCatalogPage advances duplicate pages instead of ending immediately:com.unspooled.app.domain.model.CatalogRowPaginationTest","<init>:com.unspooled.app.domain.model.CatalogRowPaginationTest","CatalogRowPaginationTest:com.unspooled.app.domain.model","mergeCatalogPage advances by returned item count without changing skip step:com.unspooled.app.domain.model.CatalogRowPaginationTest"],"src/test/java/com/unspooled/app/domain/playback/PlaybackOrchestratorTest.kt":["mockAndroidLog:com.unspooled.app.domain.playback.PlaybackOrchestratorTest.Companion","ValidationFailed resolve result is treated as failure:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","empty streams results in Failed state:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","proxy headers from behaviorHints are passed to PlaybackPlan:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","maxAttempts limits validation candidates:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","reset clears preparation state to Idle:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","stream with null url and null debridUrl is skipped:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","NotCached resolve result is treated as failure:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","cached streams are validated before uncached when earlyExitOnCached:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","early exit on cached — stops after first cached success even with more candidates:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","MissingApiKey resolve result is treated as failure:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","<init>:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","Companion:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","<init>:com.unspooled.app.domain.playback.PlaybackOrchestratorTest.Companion","remaining candidates become fallback URLs after first success:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","Validating state is emitted during preparation:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","second candidate succeeds after first fails validation:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","unmockAndroidLog:com.unspooled.app.domain.playback.PlaybackOrchestratorTest.Companion","debridUrl is used over url when both are present:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","cached debrid stream resolves to Ready immediately:com.unspooled.app.domain.playback.PlaybackOrchestratorTest","PlaybackOrchestratorTest:com.unspooled.app.domain.playback","Error resolve result is treated as failure:com.unspooled.app.domain.playback.PlaybackOrchestratorTest"],"src/test/java/com/unspooled/app/data/addon/DefaultAddonManifestTest.kt":["resourceListSerializer_roundTrips:com.unspooled.app.data.addon.DefaultAddonManifestTest","DefaultAddonManifestTest:com.unspooled.app.data.addon","<init>:com.unspooled.app.data.addon.DefaultAddonManifestTest","parsesStringAndObjectResourceFormats:com.unspooled.app.data.addon.DefaultAddonManifestTest","debridEngineManifests_return200AndParse:com.unspooled.app.data.addon.DefaultAddonManifestTest","alwaysOnManifests_return200AndParse:com.unspooled.app.data.addon.DefaultAddonManifestTest"],"src/test/java/com/unspooled/app/data/debrid/RealDebridClientTest.kt":["mockAndroidLog:com.unspooled.app.data.debrid.RealDebridClientTest.Companion","resolveCloudItem — falls back to link when download is null:com.unspooled.app.data.debrid.RealDebridClientTest","checkInstantAvailability — cached hash returns true with qualities:com.unspooled.app.data.debrid.RealDebridClientTest","checkTokenValidity — API exception returns false:com.unspooled.app.data.debrid.RealDebridClientTest","RealDebridClientTest:com.unspooled.app.data.debrid","getDownloadUrl — status magnet_error throws:com.unspooled.app.data.debrid.RealDebridClientTest","listCloudItems — returns mapped items:com.unspooled.app.data.debrid.RealDebridClientTest","checkInstantAvailability — uncached hash returns false:com.unspooled.app.data.debrid.RealDebridClientTest","getDownloadUrl — status virus throws:com.unspooled.app.data.debrid.RealDebridClientTest","getDownloadUrl — calls selectFiles when waiting_files_selection then resolves:com.unspooled.app.data.debrid.RealDebridClientTest","getDownloadUrl — empty links list throws:com.unspooled.app.data.debrid.RealDebridClientTest","Companion:com.unspooled.app.data.debrid.RealDebridClientTest","getDownloadUrl — status dead throws:com.unspooled.app.data.debrid.RealDebridClientTest","getDownloadUrl — unrestrict returns null for both download and link:com.unspooled.app.data.debrid.RealDebridClientTest","getDownloadUrl — 40-char hash converted to magnet URI:com.unspooled.app.data.debrid.RealDebridClientTest","resolveCloudItem — unrestricts link and returns download URL:com.unspooled.app.data.debrid.RealDebridClientTest","checkInstantAvailability — empty input returns empty map:com.unspooled.app.data.debrid.RealDebridClientTest","resolveCloudItem — null playableUrl returns null:com.unspooled.app.data.debrid.RealDebridClientTest","<init>:com.unspooled.app.data.debrid.RealDebridClientTest.Companion","getDownloadUrl — downloaded with null links throws:com.unspooled.app.data.debrid.RealDebridClientTest","getDownloadUrl — resolves magnet through full lifecycle:com.unspooled.app.data.debrid.RealDebridClientTest","checkInstantAvailability — API exception returns uncached:com.unspooled.app.data.debrid.RealDebridClientTest","checkTokenValidity — valid token returns true:com.unspooled.app.data.debrid.RealDebridClientTest","<init>:com.unspooled.app.data.debrid.RealDebridClientTest","getDownloadUrl — falls back to link when download is null:com.unspooled.app.data.debrid.RealDebridClientTest","getAccountInfo — free user:com.unspooled.app.data.debrid.RealDebridClientTest","getDownloadUrl — terminal error status throws:com.unspooled.app.data.debrid.RealDebridClientTest","unmockAndroidLog:com.unspooled.app.data.debrid.RealDebridClientTest.Companion","getDownloadUrl — empty torrent ID throws:com.unspooled.app.data.debrid.RealDebridClientTest","getAccountInfo — premium user with traffic:com.unspooled.app.data.debrid.RealDebridClientTest","listCloudItems — empty list:com.unspooled.app.data.debrid.RealDebridClientTest"]}