Files
view-mate/app-phone/src/test/kotlin/pw/binom/viewmate/phone/GlassesFilesTest.kt
T
Hermes Agent 2844d6a3ac feat: разделение контента — на телефон только аудио, на очки только видео
Телефон качает audio-N.ogg (audioKeys вместо fileKeys, стадия «звук»),
очки получают DownloadFiles только с video.mkv (buildGlassesFileSpecs).
Watch проверяет готовность обоих: телефон — audioReady(), очки — как
было; отказ с подсказкой «Скачать на телефон/очки». Тесты: lib-core 19,
phone 36.
2026-08-20 01:41:43 +03:00

166 lines
5.8 KiB
Kotlin

package pw.binom.viewmate.phone
import pw.binom.viewmate.core.media.MirrorAudio
import pw.binom.viewmate.core.media.MirrorFiles
import pw.binom.viewmate.core.media.MirrorVideo
import pw.binom.viewmate.core.phone.buildDownloadFiles
import pw.binom.viewmate.core.phone.buildGlassesFileSpecs
import pw.binom.viewmate.core.protocol.DownloadPhase
import pw.binom.viewmate.core.protocol.DownloadProgress
import java.io.File
import java.nio.file.Files
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlin.test.assertTrue
class GlassesFilesTest {
private fun tempDir(): File = Files.createTempDirectory("glasses-files-test").toFile()
private fun mirrorFiles() = MirrorFiles(
video = MirrorVideo(key = "v", url = "https://s3/mirror/video.mkv"),
audios = listOf(
MirrorAudio(index = 0, key = "a0", title = "Русский", url = "https://s3/mirror/audio-0.ogg"),
MirrorAudio(index = 1, key = "a1", url = "https://s3/mirror/audio-1.ogg"),
),
)
@Test
fun buildDownloadFilesUsesPresignedUrlsAndNames() {
val msg = buildDownloadFiles(
itemId = "movie-1",
title = "Interstellar",
files = mirrorFiles(),
sizes = emptyMap(),
presign = { "$it?sig" },
)
assertEquals("movie-1", msg.itemId)
assertEquals("Interstellar", msg.title)
assertEquals(1, msg.files.size)
assertEquals("video.mkv", msg.files[0].name)
assertEquals("https://s3/mirror/video.mkv?sig", msg.files[0].url)
}
@Test
fun buildDownloadFilesFillsKnownSizes() {
val msg = buildDownloadFiles(
itemId = "movie-1",
title = "T",
files = mirrorFiles(),
sizes = mapOf("video" to 1_863_946_240L, "audio-0" to 68_157_440L),
presign = { it },
)
assertEquals(1_863_946_240L, msg.files[0].sizeBytes)
}
@Test
fun buildGlassesFileSpecsPresignsEveryFile() {
val specs = buildGlassesFileSpecs(
files = mirrorFiles(),
sizes = emptyMap(),
presign = { "signed-$it" },
)
assertEquals(1, specs.size)
assertTrue(specs.all { it.url.startsWith("signed-") })
assertEquals("video.mkv", specs.single().name)
}
@Test
fun glassesFileStateNullIsNone() {
assertEquals(FileDownloadState.NONE to 0, glassesFileState(null))
}
@Test
fun glassesFileStateMapsPhases() {
val done = DownloadProgress("i", "video.mkv", 100, 10, 10, DownloadPhase.DONE)
assertEquals(FileDownloadState.DONE to 100, glassesFileState(done))
val downloading = DownloadProgress("i", "video.mkv", 45, 450, 1000, DownloadPhase.DOWNLOADING)
assertEquals(FileDownloadState.DOWNLOADING to 45, glassesFileState(downloading))
val failed = DownloadProgress("i", "audio-0.ogg", 0, 5, 10, DownloadPhase.FAILED)
assertEquals(FileDownloadState.FAILED to 0, glassesFileState(failed))
}
@Test
fun glassesFileStateClampsDownloadingPercent() {
val p = DownloadProgress("i", "video.mkv", 150, 150, 100, DownloadPhase.DOWNLOADING)
assertEquals(FileDownloadState.DOWNLOADING to 99, glassesFileState(p))
}
@Test
fun phoneFileStateFinalExistsIsDone() {
val dir = tempDir()
val final = File(dir, "video.mkv").apply { writeBytes(ByteArray(10)) }
val part = File(dir, "video.mkv.part")
assertEquals(FileDownloadState.DONE to 100, phoneFileState(final, part))
}
@Test
fun phoneFileStatePartIsDownloading() {
val dir = tempDir()
val final = File(dir, "video.mkv")
val part = File(dir, "video.mkv.part").apply { writeBytes(ByteArray(10)) }
assertEquals(FileDownloadState.DOWNLOADING to 0, phoneFileState(final, part))
}
@Test
fun phoneFileStateNoneWhenNothing() {
val dir = tempDir()
assertEquals(FileDownloadState.NONE to 0, phoneFileState(File(dir, "video.mkv"), File(dir, "video.mkv.part")))
}
@Test
fun glassesOverallPercentEmptyIsNull() {
assertNull(glassesOverallPercent(listOf("video.mkv", "audio-0.ogg"), emptyMap(), emptyMap()))
}
@Test
fun glassesOverallPercentAllDoneIsHundred() {
val names = listOf("video.mkv", "audio-0.ogg")
val perFile = mapOf(
"video.mkv" to DownloadProgress("i", "video.mkv", 100, 100, 100, DownloadPhase.DONE),
"audio-0.ogg" to DownloadProgress("i", "audio-0.ogg", 100, 50, 50, DownloadPhase.DONE),
)
assertEquals(100, glassesOverallPercent(names, emptyMap(), perFile))
}
@Test
fun glassesOverallPercentUsesKnownSizes() {
val names = listOf("video.mkv", "audio-0.ogg")
val known = mapOf("video.mkv" to 100L, "audio-0.ogg" to 100L)
val perFile = mapOf(
"video.mkv" to DownloadProgress("i", "video.mkv", 100, 100, 100, DownloadPhase.DONE),
"audio-0.ogg" to DownloadProgress("i", "audio-0.ogg", 25, 25, 100, DownloadPhase.DOWNLOADING),
)
assertEquals(62, glassesOverallPercent(names, known, perFile)) // 125/200
}
@Test
fun glassesOverallPercentFallsBackToStartedTotals() {
val names = listOf("video.mkv", "audio-0.ogg")
val perFile = mapOf(
"video.mkv" to DownloadProgress("i", "video.mkv", 50, 50, 100, DownloadPhase.DOWNLOADING),
)
assertEquals(50, glassesOverallPercent(names, emptyMap(), perFile))
}
@Test
fun glassesLivePercentRejectsEmpty() {
assertNull(glassesLivePercent(emptyMap()))
}
@Test
fun glassesLivePercentAllDoneIsHundred() {
val perFile = mapOf(
"video.mkv" to DownloadProgress("i", "video.mkv", 100, 100, 100, DownloadPhase.DONE),
)
assertEquals(100, glassesLivePercent(perFile))
}
}