Add pytest suite and CI (roadmap A1)
37 headless tests covering the logic that is cheap to break: - split planner: plan_disc_split, chapter helpers (whole-fit, multi-disc partition, single-movie chapter/even-cut split, contiguous coverage) - High-profile fill-disc bitrate math (disc count + bounds + capacity) - ffmpeg command generation: profiles, text/image hardsub, 2-pass, nice, progress-to-file, even pad/crop + positive offsets, -ss seek, and the AC3 448k audio-clamp regression - ffprobe subtitle detection: text/image classification, tags/disposition tests/conftest.py makes the in-tree package importable and installs the gettext _ builtin so modules run headless. Forgejo Actions workflow runs the suite on push/PR. Update CLAUDE.md's testing section accordingly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
b5a6cfe25f
commit
691664095b
9 changed files with 559 additions and 8 deletions
82
tests/test_ffprobe_detection.py
Normal file
82
tests/test_ffprobe_detection.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
"""Tests for embedded subtitle detection in ffprobe.process_json."""
|
||||
|
||||
import json
|
||||
import devedeng.ffprobe
|
||||
|
||||
|
||||
def _probe(streams):
|
||||
p = devedeng.ffprobe.ffprobe()
|
||||
data = json.dumps({"streams": streams})
|
||||
err = p.process_json("/movies/input.mkv", data)
|
||||
return p, err
|
||||
|
||||
|
||||
def _video(index=0, duration="120.0"):
|
||||
return {"index": index, "codec_type": "video", "codec_name": "h264",
|
||||
"width": 1920, "height": 1080, "avg_frame_rate": "24/1",
|
||||
"duration": duration}
|
||||
|
||||
|
||||
def _audio(index=1):
|
||||
return {"index": index, "codec_type": "audio", "codec_name": "aac",
|
||||
"sample_rate": "48000"}
|
||||
|
||||
|
||||
def _sub(index, codec, language="eng", title="", default=0, forced=0):
|
||||
return {"index": index, "codec_type": "subtitle", "codec_name": codec,
|
||||
"tags": {"language": language, "title": title},
|
||||
"disposition": {"default": default, "forced": forced}}
|
||||
|
||||
|
||||
def test_no_subtitles_empty_list():
|
||||
p, err = _probe([_video(), _audio()])
|
||||
assert err is False
|
||||
assert p.subtitle_tracks == []
|
||||
|
||||
|
||||
def test_text_subtitle_classified_text():
|
||||
p, _ = _probe([_video(), _audio(), _sub(2, "subrip", "eng", default=1)])
|
||||
assert len(p.subtitle_tracks) == 1
|
||||
t = p.subtitle_tracks[0]
|
||||
assert t["index"] == 2
|
||||
assert t["codec"] == "subrip"
|
||||
assert t["language"] == "eng"
|
||||
assert t["kind"] == "text"
|
||||
assert t["default"] is True
|
||||
assert t["forced"] is False
|
||||
|
||||
|
||||
def test_image_subtitles_classified_image():
|
||||
for codec in ("hdmv_pgs_subtitle", "dvd_subtitle", "dvdsub", "pgssub", "xsub"):
|
||||
p, _ = _probe([_video(), _audio(), _sub(2, codec)])
|
||||
assert p.subtitle_tracks[0]["kind"] == "image", codec
|
||||
|
||||
|
||||
def test_various_text_codecs_classified_text():
|
||||
for codec in ("subrip", "ass", "ssa", "mov_text", "webvtt"):
|
||||
p, _ = _probe([_video(), _audio(), _sub(2, codec)])
|
||||
assert p.subtitle_tracks[0]["kind"] == "text", codec
|
||||
|
||||
|
||||
def test_multiple_subtitle_tracks_in_order():
|
||||
p, _ = _probe([
|
||||
_video(), _audio(),
|
||||
_sub(2, "subrip", "eng", default=1),
|
||||
_sub(3, "hdmv_pgs_subtitle", "fre", forced=1),
|
||||
_sub(4, "ass", "jpn", title="Signs"),
|
||||
])
|
||||
assert [t["index"] for t in p.subtitle_tracks] == [2, 3, 4]
|
||||
assert [t["kind"] for t in p.subtitle_tracks] == ["text", "image", "text"]
|
||||
assert p.subtitle_tracks[1]["forced"] is True
|
||||
assert p.subtitle_tracks[2]["title"] == "Signs"
|
||||
|
||||
|
||||
def test_missing_tags_and_disposition_defaults():
|
||||
# a subtitle stream with no tags/disposition must not crash
|
||||
p, _ = _probe([_video(), _audio(),
|
||||
{"index": 2, "codec_type": "subtitle",
|
||||
"codec_name": "subrip"}])
|
||||
t = p.subtitle_tracks[0]
|
||||
assert t["language"] == ""
|
||||
assert t["default"] is False
|
||||
assert t["forced"] is False
|
||||
Loading…
Add table
Add a link
Reference in a new issue