MediaProbe's two-probe merge is untestable for want of one internal, while its sibling carries the argument for it #177

Closed
opened 2026-09-02 02:15:20 +00:00 by JMR-dev · 0 comments
JMR-dev commented 2026-09-02 02:15:20 +00:00 (Migrated from github.com)

MediaProbe's two-probe merge escaped the pattern the rest of the file follows

MediaProbe.probe (app/src/main/java/org/libremediaconverter/convert/MediaProbe.kt:52-93) runs
probeWithExtractor and probeWithFFprobe independently and then merges them:

val videoCodec = extracted?.videoCodec ?: info?.videoCodec        // :56
val audioCodec = extracted?.audioCodec ?: info?.audioCodec        // :57
val kind = classify(extracted, info)                               // :58
durationMs = maxOf(extracted?.durationMs ?: 0L, info?.durationMs ?: 0L)   // :71
width = extracted?.width ?: info?.width ?: 0                       // :74

RemuxTest (androidTest) reaches IMAGE / VIDEO / AUDIO_ONLY against real fixtures — but always with
one probe supplying the answer and the other agreeing or also failing. Nothing anywhere constructs
a disagreement.
MediaProbe is the largest single miss in the coverage report (35 lines,
72 branches), and while most of the remainder is the FFprobe half and stays device-bound, this
merge is pure and is not.

Why it escaped: one missing internal

Extracted is deliberately internal (:100) with a KDoc saying exactly why — so the JVM test
source set can name it
. classify (:86) is private and its second parameter type
FFprobeInfo (:165) is a private class. That is the whole reason this branch matrix is
untestable while extractedFrom, containerFrom, isImageFormat and shortName all have tests.

Seam: widen classify and FFprobeInfo to internal, matching the sibling that already
carries the argument for it.

What to pin once the seam exists

  • info?.isImage == true overriding a real extracted.videoCodec (:87). isImageFormat's own
    KDoc warns a false positive here "makes the source-info card describe a video as an image", and
    nothing checks the priority order.
  • Each elvis direction at :56-57 — extractor fails and FFprobe answers, and the reverse.
  • maxOf across the two probes at :71. A different rule from the already-tested max within
    one probe (MediaProbeTrackWalkTest:71-83).
  • Width/height precedence at :74-75, and hasVideo = videoCodec != null at :70, which feeds
    both CopyPlanner and FileCard.
  • The final else -> InputKind.UNPARSEABLE at :92 — "parsed, but with no stream either probe
    recognised". Its input is already built in the suite:
    MediaProbe.extractedFrom(emptyList()) at MediaProbeTrackWalkTest:140-148 returns
    Extracted(null, null, 0, 0, 0); it has simply never been handed to classify.

Acceptance: the mutations that must go red

Reorder classify's first two arms so isImage no longer wins; flip an elvis at :56; change
maxOf to extracted?.durationMs ?: 0L.

## MediaProbe's two-probe merge escaped the pattern the rest of the file follows `MediaProbe.probe` (`app/src/main/java/org/libremediaconverter/convert/MediaProbe.kt:52-93`) runs `probeWithExtractor` and `probeWithFFprobe` independently and then merges them: ```kotlin val videoCodec = extracted?.videoCodec ?: info?.videoCodec // :56 val audioCodec = extracted?.audioCodec ?: info?.audioCodec // :57 val kind = classify(extracted, info) // :58 durationMs = maxOf(extracted?.durationMs ?: 0L, info?.durationMs ?: 0L) // :71 width = extracted?.width ?: info?.width ?: 0 // :74 ``` `RemuxTest` (androidTest) reaches IMAGE / VIDEO / AUDIO_ONLY against real fixtures — but always with one probe supplying the answer and the other agreeing or also failing. **Nothing anywhere constructs a disagreement.** MediaProbe is the largest single miss in the coverage report (35 lines, 72 branches), and while most of the remainder is the FFprobe half and stays device-bound, this merge is pure and is not. ## Why it escaped: one missing `internal` `Extracted` is deliberately `internal` (`:100`) with a KDoc saying exactly why — *so the JVM test source set can name it*. `classify` (`:86`) is `private` and its second parameter type `FFprobeInfo` (`:165`) is a `private class`. That is the whole reason this branch matrix is untestable while `extractedFrom`, `containerFrom`, `isImageFormat` and `shortName` all have tests. **Seam: widen `classify` and `FFprobeInfo` to `internal`,** matching the sibling that already carries the argument for it. ## What to pin once the seam exists - `info?.isImage == true` overriding a real `extracted.videoCodec` (`:87`). `isImageFormat`'s own KDoc warns a false positive here *"makes the source-info card describe a video as an image"*, and nothing checks the priority order. - Each elvis direction at `:56-57` — extractor fails and FFprobe answers, and the reverse. - `maxOf` across the **two probes** at `:71`. A different rule from the already-tested max *within* one probe (`MediaProbeTrackWalkTest:71-83`). - Width/height precedence at `:74-75`, and `hasVideo = videoCodec != null` at `:70`, which feeds both `CopyPlanner` and `FileCard`. - The final `else -> InputKind.UNPARSEABLE` at `:92` — "parsed, but with no stream either probe recognised". Its input is **already built** in the suite: `MediaProbe.extractedFrom(emptyList())` at `MediaProbeTrackWalkTest:140-148` returns `Extracted(null, null, 0, 0, 0)`; it has simply never been handed to `classify`. ## Acceptance: the mutations that must go red Reorder `classify`'s first two arms so `isImage` no longer wins; flip an elvis at `:56`; change `maxOf` to `extracted?.durationMs ?: 0L`.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: JMR-dev/LibreMediaConverter#177