This commit is contained in:
ponzischeme89
2026-08-11 15:18:26 +12:00
parent 594159c0ae
commit 5e5849f985
33 changed files with 1143 additions and 241 deletions
@@ -28,6 +28,16 @@ import org.junit.Test
* side, this fails before a TV ever sees it.
*/
class GatewayPayloadTest {
@Test
fun `partially populated items decode without inventing an identity`() {
val item = json.decodeFromString<BaseItem>(
"""{"Name":"Incomplete","Type":"Movie"}""",
)
assertEquals("", item.id)
assertEquals("Incomplete", item.name)
}
@Test
fun `decodes server formatted movie rating sources and scales`() {
val response = json.decodeFromString<GatewayMovieRatings>(
@@ -545,7 +555,11 @@ class GatewayPayloadTest {
},
"title": "Westworld The Bicameral Mind",
"url": "https://emby.example/Videos/11/stream?static=true",
"resumePositionMs": 0
"resumePositionMs": 0,
"subtitleDownloadAvailable": true,
"trickplayAvailable": true,
"skipIntroAvailable": true,
"endCreditsAvailable": true
}
""".trimIndent(),
)
@@ -556,6 +570,10 @@ class GatewayPayloadTest {
assertEquals("S2 · E5", next.item.episodeCode)
assertEquals(0L, next.resumePositionMs)
assertTrue(next.url.startsWith("https://emby.example/Videos/11/stream"))
assertTrue(next.subtitleDownloadAvailable)
assertTrue(next.trickplayAvailable)
assertTrue(next.skipIntroAvailable)
assertTrue(next.endCreditsAvailable)
}
@Test
@@ -40,6 +40,14 @@ class ListKeysTest {
assertEquals(emptyList<BaseItem>(), emptyList<BaseItem>().distinctForKeys(BaseItem::id))
}
@Test
fun `items without identities are removed before lazy rendering`() {
val sanitised = listOf(row("row", BaseItem(name = "Incomplete"), item("valid")))
.sanitisedRows()
assertEquals(listOf("valid"), sanitised.single().items.map(BaseItem::id))
}
// Two rows under one id crash the launcher's own LazyColumn — which the recommendation
// refresh could produce by appending a freshly built row beside the one it was meant to
// replace.
@@ -48,6 +48,16 @@ class PlaybackRecoveryTest {
assertTrue(failure.canAutoRetry)
}
@Test
fun malformedContainersDoNotLoopThroughTranscodingRetries() {
val failure = describePlaybackFailure(
PlaybackException.ERROR_CODE_PARSING_CONTAINER_MALFORMED,
)
assertFalse(failure.canAutoRetry)
assertFalse(failure.requiresTranscode)
}
@Test
fun automaticRetriesAreBoundedAndBackOff() {
assertEquals(1_000L, automaticRetryDelayMs(1))
@@ -63,4 +73,17 @@ class PlaybackRecoveryTest {
assertFalse(shouldRecoverProlongedRebuffer(true, false, true, false))
assertFalse(shouldRecoverProlongedRebuffer(true, false, false, true))
}
@Test
fun replacementSessionDetectionKeepsSameSessionStreamSwapsTogether() {
assertFalse(
playbackSessionChanged("episode", "source-a", "session", "episode", "source-b", "session"),
)
assertTrue(
playbackSessionChanged("episode", "source-a", "old", "episode", "source-b", "new"),
)
assertTrue(
playbackSessionChanged("episode", "source-a", "", "episode", "source-b", ""),
)
}
}
@@ -57,5 +57,13 @@ class PlayerTimingTest {
PlaybackCompletionAction.PLAY_NEXT,
playbackCompletionAction(hasNextEpisode = true, nextUpDismissed = false),
)
assertEquals(
PlaybackCompletionAction.WAIT_FOR_NEXT,
playbackCompletionAction(
hasNextEpisode = false,
nextUpDismissed = false,
nextLookupInFlight = true,
),
)
}
}