Skip to content

test: close the video-surface confidence gaps — capture E2E on both platforms + unit suites - #81

Merged
onevcat merged 2 commits into
mainfrom
test/video-confidence
Jul 29, 2026
Merged

onevcat merged 2 commits into
mainfrom
test/video-confidence

Conversation

@onevcat

@onevcat onevcat commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Motivation

Pre-release confidence pass over the video stack that just landed in #79/#80. The audit (per-file llvm-cov on make test) found the pure-logic core in good shape but three blind spots worth closing before shipping.

Audit result

Area Before After
AnnexBStreamParser 98.8% 98.8% ✓
H264MuxingPipeline 89.0% 89.0% ✓
H264PassthroughRecorder 91.8% 91.8% ✓
VideoOutputFile 0% 95.7%
VideoRecordingOptions 62.5% 93.8%
ProcessControl 14.7% 66.2%
VideoCommandSupport (frame utils + encoder) 5.9% 25.2%

The remainder of VideoCommandSupport is H264StreamRecorder's AVAssetWriter encoder body — reachable only through the screencap/screenshot fallback paths, which can't be forced without breaking screenrecord/FBSimulator capture; its policy pieces (estimateBitrate, waitUntilReady stall timeout) are unit-pinned and the happy paths run under live E2E. SignalObserver is likewise left to the live SIGTERM E2E paths. Command-orchestration files (backend verbs, forwarders) intentionally carry their weight in E2E, not unit numbers.

E2E additions (the real gaps)

Screenshot had no live suite on either platform, and Android record-video had none:

  • ScreenshotTests (iOS runner): PNG-magic file capture, --json envelope whose data.path is verified on disk, directory-target stamping.
  • AndroidScreenshotTests: bridge capture to file, --output - raw PNG bytes on stdout, top-level serial routing.
  • AndroidRecordVideoTests: AVAsset-loadable MP4 with a video track from both android record-video and the top-level route, plus a forced segment restart (SIM_USE_SCREENRECORD_TIME_LIMIT=2 over a 6 s recording) that must still finalize one continuous MP4.

With these, every capture surface (screenshot / record-video / stream-video) × platform (iOS / Android) has a live E2E suite; stream-video's landed in #80 (StreamVideoTests iOS, AndroidStreamVideoTests).

Unit additions

VideoOutputFileTests (default stamping, tilde expansion, directory targets, stale-file replacement, intermediate dirs), VideoRecordingOptionsTests (range boundaries incl. the 30-vs-60 FPS stream/record split), VideoFrameProcessingTests (decode/dimension math, the byte-for-byte pass-through fast path, quality/scale re-encode — the scale path renders via NSImage.lockFocus at the host's backing scale factor, so tests pin re-encode + aspect ratio rather than absolute pixels), ProcessControlTests (OnceFlag single-winner race, cancellableSleep early wake).

Verification

  • make test: 1252 green (was 1222), zero warnings.
  • All 12 new E2E cases run live: iOS suite against a booted iPhone 17 Pro, Android suites against emulator-5554 (bridge installed via android init).
  • New suites registered in scripts/test-runner.sh / scripts/test-runner-android.sh so make e2e-ios / make e2e-android pick them up.

🤖 Generated with Claude Code

…latforms + unit suites

Pre-release audit of the video stack found the pure-logic core well
covered (AnnexBStreamParser 98.8%, H264MuxingPipeline 89.0%,
H264PassthroughRecorder 91.8%) but three blind spots:

E2E: screenshot had no live suite on either platform, and Android
record-video had none (stream-video landed with one in #80). Added:

- ScreenshotTests (iOS runner): PNG-magic file capture, --json envelope
  whose path is verified on disk, directory-target stamping.
- AndroidScreenshotTests: bridge capture to file, `--output -` raw PNG
  on stdout, top-level serial routing.
- AndroidRecordVideoTests: AVAsset-loadable MP4 with a video track from
  both the android subcommand and the top-level route, plus a forced
  segment restart (SIM_USE_SCREENRECORD_TIME_LIMIT=2) that must still
  finalize one continuous MP4.

Unit: VideoOutputFile was at 0% despite being pure path logic — now
95.7% (default stamping, tilde expansion, directory targets, stale-file
replacement, intermediate dirs). VideoRecordingOptions boundary pins
(93.8%), VideoFrameUtilities frame processing incl. the byte-for-byte
pass-through fast path (the scale path renders via NSImage.lockFocus at
the host's backing scale factor, so tests pin re-encode + aspect ratio,
not absolute pixels), and ProcessControl primitives (66.2%; SignalObserver
left to the live SIGTERM E2E paths).

H264StreamRecorder's AVAssetWriter encoder body stays E2E-only: it is
reachable only through the screencap/screenshot fallbacks, which cannot
be forced without breaking screenrecord.

1252 unit tests green; all 12 new/E2E cases verified live against a
booted iPhone 17 Pro simulator and emulator-5554.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: onevcat <onevcat@gmail.com>
Review caught that the segment-restart case only proved "restart logged
+ file has a video track" — a muxer that dropped every post-restart
frame would still pass. The suggested duration/isPlayable checks alone
would not close that hole either: finish(stopHostTime:) re-appends the
last access unit at the stop time, so a segment-1-only file still
reports full wall-clock duration and stays playable.

The discriminating pin reads the real muxed samples via a pass-through
AVAssetReader: at least one sample PTS must land inside the
post-restart window (2.5-5.5 s), where segment-1 frames (<= ~2.3 s) and
the trailing re-append (~6 s) cannot reach; sample PTS must also be
non-decreasing. Because screenrecord is VFR and a static screen can
leave a segment frameless, the test drives adb input swipes for the
whole recording so every segment has frames to contribute. duration >
3 s and isPlayable are asserted too, as supporting signals.

Verified live against emulator-5554; 1252 unit tests green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Signed-off-by: onevcat <onevcat@gmail.com>
@onevcat
onevcat merged commit 9a219a9 into main Jul 29, 2026
4 checks passed
@onevcat
onevcat deleted the test/video-confidence branch July 29, 2026 03:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant