Assert the join failure message against a real FFmpeg session #221

Merged
JMR-dev merged 3 commits from test/join-failure-message-on-device into main 2026-09-06 13:51:00 +00:00
JMR-dev commented 2026-09-06 02:13:08 +00:00 (Migrated from github.com)

Finishes the loose end #217 left: "The join legs are worth running locally … noting that I have not
done so."

Running them would not have answered it

Nothing on either source set drove a real join failure. The message unified in #203 was asserted
only in SessionOutcomeTest, against values handed to sessionOutcome directly — and CI had already
run all five instrumented legs green on the merged commit, so the join happy path was covered.
The outstanding item was a coverage gap, not an execution gap. A local run would have been theatre.

What the new test pins

ConcatEngineTest.aFailedJoinReportsTheReturnCodeAndWhatFFmpegSaid forces a failure with an input
that does not exist — the concat demuxer rejects that identically on every FFmpeg build, unlike
malformed media whose handling varies — and asserts the message:

  1. names the operation and carries the return code (Joining failed (…)), and
  2. has detail after it.

Clause 2 is the device-only half. getReturnCode, getFailStackTrace and getAllLogsAsString are
native reads against a real FFmpegKit session. If the log tail came back empty on a device, users
would get Joining failed (1): with nothing after the colon and every JVM test would still pass.

What it deliberately does not pin, and why

Which detail source wins. On an ordinary non-zero return code FFmpegKit reports no fail stack
trace, so the stack-trace-first rule and the log-tail-first rule produce the same text — no
assertion here can distinguish them. SessionOutcomeTest pins that ordering, where both sources can
be non-blank at once.

Asserting it here would be a test whose KDoc claims more than it checks, which is the probeForConcat
mistake wave 3 caught and CLAUDE.md records. The KDoc says so in terms.

Verification — local API 33 emulator

run shape result
with the test expected 61, received 61, failed 0, completed cleanly: yes green
failStackTrace = { null }, logTail = { null } in ConcatEngine failed 1 red
AssertionError: the message stopped at the return code and told the user nothing,
was: 'Joining failed (1): '

The mutation output is the argument for the test's shape: the prefix and the return code survive
it — those come from sessionOutcome, which the JVM test already covers — and only the device-only
claim goes red. It also confirms real FFmpeg returns rc=1 here, so the fixture forces what it says.

Mutation restored; the diff is androidTest only, no production change.

Gate: assembleDebug + testDebugUnitTest + compileDebugAndroidTestKotlin + ktlintCheck +
detekt + lintDebug — green.

🤖 Generated with Claude Code

Finishes the loose end #217 left: *"The join legs are worth running locally … noting that I have not done so."* ## Running them would not have answered it Nothing on either source set drove a real join **failure**. The message unified in #203 was asserted only in `SessionOutcomeTest`, against values handed to `sessionOutcome` directly — and CI had already run all five instrumented legs green on the merged commit, so the join *happy* path was covered. The outstanding item was a coverage gap, not an execution gap. A local run would have been theatre. ## What the new test pins `ConcatEngineTest.aFailedJoinReportsTheReturnCodeAndWhatFFmpegSaid` forces a failure with an input that does not exist — the concat demuxer rejects that identically on every FFmpeg build, unlike malformed media whose handling varies — and asserts the message: 1. names the operation and carries the return code (`Joining failed (`…`)`), and 2. **has detail after it.** Clause 2 is the device-only half. `getReturnCode`, `getFailStackTrace` and `getAllLogsAsString` are native reads against a real `FFmpegKit` session. If the log tail came back empty on a device, users would get `Joining failed (1): ` with nothing after the colon and every JVM test would still pass. ## What it deliberately does not pin, and why **Which detail source wins.** On an ordinary non-zero return code FFmpegKit reports no fail stack trace, so the stack-trace-first rule and the log-tail-first rule produce the *same* text — no assertion here can distinguish them. `SessionOutcomeTest` pins that ordering, where both sources can be non-blank at once. Asserting it here would be a test whose KDoc claims more than it checks, which is the `probeForConcat` mistake wave 3 caught and CLAUDE.md records. The KDoc says so in terms. ## Verification — local API 33 emulator | | run shape | result | |---|---|---| | with the test | `expected 61, received 61, failed 0, completed cleanly: yes` | green | | `failStackTrace = { null }`, `logTail = { null }` in `ConcatEngine` | `failed 1` | red | ``` AssertionError: the message stopped at the return code and told the user nothing, was: 'Joining failed (1): ' ``` The mutation output is the argument for the test's shape: the prefix and the return code **survive** it — those come from `sessionOutcome`, which the JVM test already covers — and only the device-only claim goes red. It also confirms real FFmpeg returns rc=1 here, so the fixture forces what it says. Mutation restored; the diff is androidTest only, no production change. Gate: `assembleDebug` + `testDebugUnitTest` + `compileDebugAndroidTestKotlin` + `ktlintCheck` + `detekt` + `lintDebug` — green. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.