Repository navigation
feat(tests): check complete video exports - #200
DonIsmaelito wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
2 issues found across 3 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="tests/test_video_exports.py">
<violation number="1" location="tests/test_video_exports.py:23">
P3: A command that hangs past the 90s timeout raises `subprocess.TimeoutExpired`, which is not caught here, so the forced-failure diagnostic this helper exists to produce (command + stderr tail) never appears and the test fails with a raw traceback. Catch `TimeoutExpired` and re-raise it as the same AssertionError with the command name.</violation>
<violation number="2" location="tests/test_video_exports.py:45">
P3: The capability gate checks ffmpeg/ffprobe, the libass `subtitles` filter, and libx264, but never checks that fontconfig has any installed fonts. The caption assertions (`white(samples[0.5]) > 150`) fail silently-mysterious when libass has no font, producing an unrelated pixel-check failure instead of the skip-with-hint this gate and tests/README.md promise. Add a fontconfig check (e.g., non-empty `fc-list` output) to the `missing` list.</violation>
</file>
Heads up: you’ve reached your flex budget. Increase your flex budget or wait for usage to reset.
Fix all with cubic | Re-trigger cubic
| class VideoExportTests(unittest.TestCase): | ||
| @classmethod | ||
| def setUpClass(cls): | ||
| missing = [name for name in ("ffmpeg", "ffprobe") if shutil.which(name) is None] |
There was a problem hiding this comment.
P3: The capability gate checks ffmpeg/ffprobe, the libass subtitles filter, and libx264, but never checks that fontconfig has any installed fonts. The caption assertions (white(samples[0.5]) > 150) fail silently-mysterious when libass has no font, producing an unrelated pixel-check failure instead of the skip-with-hint this gate and tests/README.md promise. Add a fontconfig check (e.g., non-empty fc-list output) to the missing list.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/test_video_exports.py, line 45:
<comment>The capability gate checks ffmpeg/ffprobe, the libass `subtitles` filter, and libx264, but never checks that fontconfig has any installed fonts. The caption assertions (`white(samples[0.5]) > 150`) fail silently-mysterious when libass has no font, producing an unrelated pixel-check failure instead of the skip-with-hint this gate and tests/README.md promise. Add a fontconfig check (e.g., non-empty `fc-list` output) to the `missing` list.</comment>
<file context>
@@ -0,0 +1,167 @@
+class VideoExportTests(unittest.TestCase):
+ @classmethod
+ def setUpClass(cls):
+ missing = [name for name in ("ffmpeg", "ffprobe") if shutil.which(name) is None]
+ if not missing:
+ filters = run(["ffmpeg", "-hide_banner", "-filters"]).decode()
</file context>
|
|
||
| # Surface the failing media command and its diagnostics without an unbounded log. | ||
| def run(command): | ||
| result = subprocess.run([str(part) for part in command], capture_output=True, timeout=90) |
There was a problem hiding this comment.
P3: A command that hangs past the 90s timeout raises subprocess.TimeoutExpired, which is not caught here, so the forced-failure diagnostic this helper exists to produce (command + stderr tail) never appears and the test fails with a raw traceback. Catch TimeoutExpired and re-raise it as the same AssertionError with the command name.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/test_video_exports.py, line 23:
<comment>A command that hangs past the 90s timeout raises `subprocess.TimeoutExpired`, which is not caught here, so the forced-failure diagnostic this helper exists to produce (command + stderr tail) never appears and the test fails with a raw traceback. Catch `TimeoutExpired` and re-raise it as the same AssertionError with the command name.</comment>
<file context>
@@ -0,0 +1,167 @@
+
+# Surface the failing media command and its diagnostics without an unbounded log.
+def run(command):
+ result = subprocess.run([str(part) for part in command], capture_output=True, timeout=90)
+ if result.returncode:
+ raise AssertionError(f"Command failed: {command}\n{result.stderr.decode(errors='replace')[-4000:]}")
</file context>
Why
The editing checks should detect failures in actual exported files. This extends #198 with real FFmpeg exports instead of relying only on mocked commands and subtitle string tests.
Changes
Validation: all 29 tests pass on Python 3.12, including the three real-export tests and their portrait/rotation subtests. Tested with an FFmpeg build containing libass. The rotation fixture checks its actual display matrix and supports both the legacy metadata option and newer FFmpeg display option. Whitespace checks pass. No provider calls or downloads are used by the tests.
Limits
Builds on #198 and includes its small workflow commit until that PR lands. Compare only this change.
Fixtures use the draft preset and skip loudness normalization. They do not certify visual taste, final-quality encoding, long-edit synchronization, or every codec. The legacy copy-concat path retains its existing AAC padding; the two-second fixture allows up to 100 ms of total duration or audio/video difference. GitHub-hosted Python 3.10/3.12 results remain to be verified; fork workflows may require maintainer approval.
Summary by cubic
Adds real FFmpeg export tests that run the public render command on generated media and fully decode each output to verify clip order, overlay timing, visible captions, audio placement, frame rate, portrait/rotation, and unchanged source bytes. Missing media capabilities skip locally but fail CI, so exports can't silently go untested.
tests/README.mddocuments requirements, usage, and known limitations like the legacy AAC padding tolerance.Written for commit 059a471. Summary will update on new commits.