readMediaInformation was 114 missed instructions and 24 missed branches — the second-largest block on the wave-4 report — and exactly one line of it needed a device:
Everything after it reads an ordinary object, so it moves into ffprobeInfoFrom(info: MediaInformation) and the edge keeps the call plus the null check.
JVM-safe, verified rather than assumed.javap over the committed AAR's runtime jar: MediaInformation(JSONObject, List<StreamInformation>, List<Chapter>) and StreamInformation(JSONObject) are plain public constructors, and neither class's <clinit> loads the native library.
The decision worth reaching
containerFrom(formatName, video?.getCodec()). FFprobe reports matroska,webm for both MKV and WebM — they share a demuxer — so the video codec is the only thing separating them. containerFrom has thirty-three covered branches and not one can notice that argument being dropped: the mistake is at the call, not in the callee. Every existing containerFrom test stays green while every VP9 WebM quietly becomes an MKV.
Two things the tests found rather than confirmed
The format properties are nested under "format".getFormat() resolves through getStringFormatProperty, not off the top-level object. The first fixture put the keys at the top level and four cases failed with a null container. The helper's KDoc records it so the next fixture doesn't rediscover it.
One mutation survived the first pass. Reading dimensions as streams.firstNotNullOfOrNull { it.getWidth() } instead of video?.getWidth() gave the same answer, because the fixture put the dimensions on the chosen video stream — which was also the first stream carrying any. The two readings agreed, so the test could not tell them apart.
Separating them needs a chosen video stream with no dimensions and a later one that has them — a real shape, since FFprobe omits width/height for a stream it could not measure. That is now its own test, and the mutation reddens it.
Acceptance: mutations run and restored
mutation
red
drop the video codec argument to containerFrom
1
take the last video stream instead of the first
1
read dimensions from any stream, not the chosen one
0 → 1 after the new case
let an unparseable duration throw instead of answering zero
1
Scope
Does not touch probeWithFFprobe's two catch arms. The Error arm is already driven by MediaProbeNativeLoadTest and ConversionViewModelProbeFailureTest; the throw e rethrow is unreachable on the JVM because the first FFmpegKit touch always yields the native-load Error first.
Verification
assembleDebug + testDebugUnitTest (full suite) + compileDebugAndroidTestKotlin + ktlintCheck + detekt + lintDebug — green. One ktlint complaint fixed with ktlintFormat, not by hand.
Closes #195. **Touches production**, like #210.
## The split
`readMediaInformation` was 114 missed instructions and 24 missed branches — the second-largest block on the wave-4 report — and **exactly one line of it needed a device**:
```kotlin
FFprobeKit.getMediaInformation(path).getMediaInformation()
```
Everything after it reads an ordinary object, so it moves into `ffprobeInfoFrom(info: MediaInformation)` and the edge keeps the call plus the null check.
**JVM-safe, verified rather than assumed.** `javap` over the committed AAR's runtime jar: `MediaInformation(JSONObject, List<StreamInformation>, List<Chapter>)` and `StreamInformation(JSONObject)` are plain public constructors, and neither class's `<clinit>` loads the native library.
## The decision worth reaching
`containerFrom(formatName, video?.getCodec())`. FFprobe reports `matroska,webm` for **both** MKV and WebM — they share a demuxer — so the video codec is the only thing separating them. `containerFrom` has thirty-three covered branches and **not one can notice that argument being dropped**: the mistake is at the call, not in the callee. Every existing `containerFrom` test stays green while every VP9 WebM quietly becomes an MKV.
## Two things the tests found rather than confirmed
**The format properties are nested under `"format"`.** `getFormat()` resolves through `getStringFormatProperty`, not off the top-level object. The first fixture put the keys at the top level and four cases failed with a null container. The helper's KDoc records it so the next fixture doesn't rediscover it.
**One mutation survived the first pass.** Reading dimensions as `streams.firstNotNullOfOrNull { it.getWidth() }` instead of `video?.getWidth()` gave the same answer, because the fixture put the dimensions on the chosen video stream — which was also the first stream carrying any. The two readings agreed, so the test could not tell them apart.
Separating them needs a chosen video stream with **no** dimensions and a later one that has them — a real shape, since FFprobe omits `width`/`height` for a stream it could not measure. That is now its own test, and the mutation reddens it.
## Acceptance: mutations run and restored
| mutation | red |
|---|---|
| drop the video codec argument to `containerFrom` | 1 |
| take the **last** video stream instead of the first | 1 |
| read dimensions from any stream, not the chosen one | **0 → 1** after the new case |
| let an unparseable duration throw instead of answering zero | 1 |
## Scope
Does not touch `probeWithFFprobe`'s two catch arms. The `Error` arm is already driven by `MediaProbeNativeLoadTest` and `ConversionViewModelProbeFailureTest`; the `throw e` rethrow is unreachable on the JVM because the first FFmpegKit touch always yields the native-load `Error` first.
## Verification
`assembleDebug` + `testDebugUnitTest` (full suite) + `compileDebugAndroidTestKotlin` + `ktlintCheck` + `detekt` + `lintDebug` — green. One ktlint complaint fixed with `ktlintFormat`, not by hand.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #195. Touches production, like #210.
The split
readMediaInformationwas 114 missed instructions and 24 missed branches — the second-largest block on the wave-4 report — and exactly one line of it needed a device:Everything after it reads an ordinary object, so it moves into
ffprobeInfoFrom(info: MediaInformation)and the edge keeps the call plus the null check.JVM-safe, verified rather than assumed.
javapover the committed AAR's runtime jar:MediaInformation(JSONObject, List<StreamInformation>, List<Chapter>)andStreamInformation(JSONObject)are plain public constructors, and neither class's<clinit>loads the native library.The decision worth reaching
containerFrom(formatName, video?.getCodec()). FFprobe reportsmatroska,webmfor both MKV and WebM — they share a demuxer — so the video codec is the only thing separating them.containerFromhas thirty-three covered branches and not one can notice that argument being dropped: the mistake is at the call, not in the callee. Every existingcontainerFromtest stays green while every VP9 WebM quietly becomes an MKV.Two things the tests found rather than confirmed
The format properties are nested under
"format".getFormat()resolves throughgetStringFormatProperty, not off the top-level object. The first fixture put the keys at the top level and four cases failed with a null container. The helper's KDoc records it so the next fixture doesn't rediscover it.One mutation survived the first pass. Reading dimensions as
streams.firstNotNullOfOrNull { it.getWidth() }instead ofvideo?.getWidth()gave the same answer, because the fixture put the dimensions on the chosen video stream — which was also the first stream carrying any. The two readings agreed, so the test could not tell them apart.Separating them needs a chosen video stream with no dimensions and a later one that has them — a real shape, since FFprobe omits
width/heightfor a stream it could not measure. That is now its own test, and the mutation reddens it.Acceptance: mutations run and restored
containerFromScope
Does not touch
probeWithFFprobe's two catch arms. TheErrorarm is already driven byMediaProbeNativeLoadTestandConversionViewModelProbeFailureTest; thethrow erethrow is unreachable on the JVM because the first FFmpegKit touch always yields the native-loadErrorfirst.Verification
assembleDebug+testDebugUnitTest(full suite) +compileDebugAndroidTestKotlin+ktlintCheck+detekt+lintDebug— green. One ktlint complaint fixed withktlintFormat, not by hand.🤖 Generated with Claude Code