Files
LibreMediaConverter/app/src/test/java/org/libremediaconverter/model/ConcatPlannerTest.kt
T
JMR-devandClaude Opus 5 dd2fcf0a19 Rename the project to LibreMediaConverter
Done now rather than later: the application ID is permanent once published --
Play treats a change as an entirely different app -- so this is the last
cheap moment to choose it.

  applicationId / namespace  dev.jasonmross.mediaconverter -> org.libremediaconverter
  source tree                java/dev/jasonmross/mediaconverter -> java/org/libremediaconverter
  gradle project             AndroidMediaConverter -> LibreMediaConverter
  theme                      Theme.MediaConverter -> Theme.LibreMediaConverter
  compose theme              MediaConverterTheme -> LibreMediaConverterTheme
  display name               "Media Converter" -> "LibreMediaConverter"

org.* rather than dev.jasonmross.* because "Libre" signals a project rather
than a personal app, and a project-owned namespace lets maintainership move
later without the identifier contradicting reality.

The source trees moved with git mv so history follows the files instead of
showing 42 deletions beside 42 additions.

Verified after the rename: 66 unit tests, and 40 instrumented tests on an
API 36 emulator, 0 failures. The built APK reports org.libremediaconverter,
and no stale jasonmross, AndroidMediaConverter or MediaConverterTheme
identifiers remain anywhere in the tree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-20 18:31:43 -05:00

84 lines
2.4 KiB
Kotlin

package org.libremediaconverter.model
import org.junit.Assert.assertEquals
import org.junit.Test
/**
* The stream-copy-vs-re-encode decision.
*
* This matters more than it looks: the `concat` demuxer does not reject mismatched
* inputs loudly, it can emit a file whose later segments are garbled. So the default
* on any doubt has to be re-encoding.
*/
class ConcatPlannerTest {
private fun clip(
video: String? = "h264",
audio: String? = "aac",
width: Int = 1920,
height: Int = 1080,
fps: Int = 30,
) = ConcatInput(video, audio, width, height, fps)
@Test
fun `identical clips can be stream copied`() {
assertEquals(
ConcatStrategy.STREAM_COPY,
ConcatPlanner.plan(listOf(clip(), clip())),
)
}
@Test
fun `a single input needs no re-encode`() {
assertEquals(ConcatStrategy.STREAM_COPY, ConcatPlanner.plan(listOf(clip())))
}
@Test
fun `different video codecs force a re-encode`() {
assertEquals(
ConcatStrategy.REENCODE,
ConcatPlanner.plan(listOf(clip(video = "h264"), clip(video = "hevc"))),
)
}
@Test
fun `different audio codecs force a re-encode`() {
assertEquals(
ConcatStrategy.REENCODE,
ConcatPlanner.plan(listOf(clip(audio = "aac"), clip(audio = "opus"))),
)
}
@Test
fun `different resolutions force a re-encode`() {
assertEquals(
ConcatStrategy.REENCODE,
ConcatPlanner.plan(listOf(clip(width = 1920, height = 1080), clip(width = 1280, height = 720))),
)
}
@Test
fun `different frame rates force a re-encode`() {
assertEquals(
ConcatStrategy.REENCODE,
ConcatPlanner.plan(listOf(clip(fps = 30), clip(fps = 60))),
)
}
@Test
fun `an unknown codec is not treated as a match`() {
// Two nulls are not evidence of agreement. Assuming they match is exactly how
// a silent corrupt concat happens.
assertEquals(
ConcatStrategy.REENCODE,
ConcatPlanner.plan(listOf(clip(video = null), clip(video = null))),
)
}
@Test
fun `a mismatch anywhere in a longer list is caught`() {
val clips = listOf(clip(), clip(), clip(), clip(width = 640, height = 480), clip())
assertEquals(ConcatStrategy.REENCODE, ConcatPlanner.plan(clips))
}
}