refactor: Spur-Fehlermeldung und yt-dlp-Fake gemeinsam nutzen
- yt_untertitel.no_track_message() für yt_untertitel.py und extract_text.py - tests/conftest.py: Fixtures fake_yt_dlp und yt_dlp_installed Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ba61434798
commit
0413455ea5
3 changed files with 74 additions and 79 deletions
42
tests/conftest.py
Normal file
42
tests/conftest.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
"""Shared fixtures: yt-dlp is always replaced by fakes (no network)."""
|
||||
import json
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def fake_yt_dlp():
|
||||
"""Factory for a subprocess.run stand-in.
|
||||
|
||||
It answers the info request with `info` and writes `vtt` where yt-dlp would
|
||||
write the subtitle file. `run.calls` records every command.
|
||||
"""
|
||||
def make(info, vtt="WEBVTT\n", write=True, fail_download=False):
|
||||
calls = []
|
||||
|
||||
def run(command, capture_output, text):
|
||||
calls.append(command)
|
||||
if "--dump-single-json" in command:
|
||||
return subprocess.CompletedProcess(command, 0, json.dumps(info), "")
|
||||
if fail_download:
|
||||
return subprocess.CompletedProcess(command, 1, "", "HTTP Error 429")
|
||||
track = command[command.index("--sub-langs") + 1]
|
||||
template = command[command.index("-o") + 1]
|
||||
if write:
|
||||
Path(template.replace("%(ext)s", f"{track}.vtt")).write_text(
|
||||
vtt, encoding="utf-8"
|
||||
)
|
||||
return subprocess.CompletedProcess(command, 0, "", "")
|
||||
|
||||
run.calls = calls
|
||||
return run
|
||||
|
||||
return make
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def yt_dlp_installed(monkeypatch):
|
||||
monkeypatch.setattr(shutil, "which", lambda name: f"/usr/bin/{name}")
|
||||
|
|
@ -1,8 +1,5 @@
|
|||
"""Tests for extract_text.py; yt-dlp is always replaced by fakes (no network)."""
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -25,26 +22,7 @@ GERMAN_VIDEO = {
|
|||
}
|
||||
|
||||
|
||||
def fake_yt_dlp(info, vtt=VTT):
|
||||
"""Stand-in for subprocess.run: answers the info request, writes the VTT file."""
|
||||
calls = []
|
||||
|
||||
def run(command, capture_output, text):
|
||||
calls.append(command)
|
||||
if "--dump-single-json" in command:
|
||||
return subprocess.CompletedProcess(command, 0, json.dumps(info), "")
|
||||
track = command[command.index("--sub-langs") + 1]
|
||||
template = command[command.index("-o") + 1]
|
||||
Path(template.replace("%(ext)s", f"{track}.vtt")).write_text(vtt, encoding="utf-8")
|
||||
return subprocess.CompletedProcess(command, 0, "", "")
|
||||
|
||||
run.calls = calls
|
||||
return run
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def yt_dlp_installed(monkeypatch):
|
||||
monkeypatch.setattr(extract_text.shutil, "which", lambda name: f"/usr/bin/{name}")
|
||||
pytestmark = pytest.mark.usefixtures("yt_dlp_installed")
|
||||
|
||||
|
||||
def run_main(monkeypatch, *args):
|
||||
|
|
@ -52,8 +30,8 @@ def run_main(monkeypatch, *args):
|
|||
extract_text.main()
|
||||
|
||||
|
||||
def test_default_language_is_original_audio(tmp_path, monkeypatch, capsys):
|
||||
run = fake_yt_dlp(GERMAN_VIDEO)
|
||||
def test_default_language_is_original_audio(fake_yt_dlp, tmp_path, monkeypatch, capsys):
|
||||
run = fake_yt_dlp(GERMAN_VIDEO, vtt=VTT)
|
||||
monkeypatch.setattr(yt.subprocess, "run", run)
|
||||
monkeypatch.chdir(tmp_path)
|
||||
run_main(monkeypatch, "-u", URL)
|
||||
|
|
@ -68,8 +46,8 @@ def test_default_language_is_original_audio(tmp_path, monkeypatch, capsys):
|
|||
assert [p.name for p in tmp_path.iterdir()] == ["output.txt"]
|
||||
|
||||
|
||||
def test_explicit_language_prefers_manual(tmp_path, monkeypatch):
|
||||
run = fake_yt_dlp(GERMAN_VIDEO)
|
||||
def test_explicit_language_prefers_manual(fake_yt_dlp, tmp_path, monkeypatch):
|
||||
run = fake_yt_dlp(GERMAN_VIDEO, vtt=VTT)
|
||||
monkeypatch.setattr(yt.subprocess, "run", run)
|
||||
target = tmp_path / "neu" / "rede.en.txt"
|
||||
run_main(monkeypatch, "-u", URL, "-l", "en", "-o", target)
|
||||
|
|
@ -78,9 +56,11 @@ def test_explicit_language_prefers_manual(tmp_path, monkeypatch):
|
|||
assert "--write-subs" in run.calls[1]
|
||||
|
||||
|
||||
def test_original_language_from_metadata_without_auto_captions(tmp_path, monkeypatch):
|
||||
def test_original_language_from_metadata_without_auto_captions(
|
||||
fake_yt_dlp, tmp_path, monkeypatch
|
||||
):
|
||||
info = {"id": "x", "language": "fr", "subtitles": {"fr": []}, "automatic_captions": {}}
|
||||
run = fake_yt_dlp(info)
|
||||
run = fake_yt_dlp(info, vtt=VTT)
|
||||
monkeypatch.setattr(yt.subprocess, "run", run)
|
||||
run_main(monkeypatch, "-u", URL, "-o", tmp_path / "out.txt")
|
||||
assert run.calls[1][run.calls[1].index("--sub-langs") + 1] == "fr"
|
||||
|
|
@ -91,14 +71,14 @@ def test_original_language_from_metadata_without_auto_captions(tmp_path, monkeyp
|
|||
(GERMAN_VIDEO, ["-l", "fr"], "Keine Untertitel in „fr“"),
|
||||
({"id": "x", "subtitles": {}, "automatic_captions": {}}, [], "Originalsprache"),
|
||||
])
|
||||
def test_no_matching_track(tmp_path, monkeypatch, info, args, message):
|
||||
monkeypatch.setattr(yt.subprocess, "run", fake_yt_dlp(info))
|
||||
def test_no_matching_track(fake_yt_dlp, tmp_path, monkeypatch, info, args, message):
|
||||
monkeypatch.setattr(yt.subprocess, "run", fake_yt_dlp(info, vtt=VTT))
|
||||
with pytest.raises(SystemExit, match=message):
|
||||
run_main(monkeypatch, "-u", URL, "-o", tmp_path / "out.txt", *args)
|
||||
assert not (tmp_path / "out.txt").exists()
|
||||
|
||||
|
||||
def test_empty_subtitles(tmp_path, monkeypatch):
|
||||
def test_empty_subtitles(fake_yt_dlp, tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(yt.subprocess, "run", fake_yt_dlp(GERMAN_VIDEO, vtt="WEBVTT\n"))
|
||||
with pytest.raises(SystemExit, match="keinen Text"):
|
||||
run_main(monkeypatch, "-u", URL, "-o", tmp_path / "out.txt")
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
"""Tests for yt_untertitel.py; yt-dlp is always replaced by fakes (no network)."""
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
|
@ -18,31 +16,7 @@ AUTO_ONLY = {
|
|||
}
|
||||
|
||||
|
||||
def fake_yt_dlp(info, write=True, fail_download=False):
|
||||
"""Stand-in for subprocess.run: answers the info request, writes the VTT file."""
|
||||
calls = []
|
||||
|
||||
def run(command, capture_output, text):
|
||||
calls.append(command)
|
||||
if "--dump-single-json" in command:
|
||||
return subprocess.CompletedProcess(command, 0, json.dumps(info), "")
|
||||
if fail_download:
|
||||
return subprocess.CompletedProcess(command, 1, "", "HTTP Error 429")
|
||||
track = command[command.index("--sub-langs") + 1]
|
||||
template = command[command.index("-o") + 1]
|
||||
if write:
|
||||
Path(template.replace("%(ext)s", f"{track}.vtt")).write_text(
|
||||
"WEBVTT\n", encoding="utf-8"
|
||||
)
|
||||
return subprocess.CompletedProcess(command, 0, "", "")
|
||||
|
||||
run.calls = calls
|
||||
return run
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def yt_dlp_installed(monkeypatch):
|
||||
monkeypatch.setattr(yt.shutil, "which", lambda name: f"/usr/bin/{name}")
|
||||
pytestmark = pytest.mark.usefixtures("yt_dlp_installed")
|
||||
|
||||
|
||||
def run_main(monkeypatch, *args):
|
||||
|
|
@ -79,7 +53,7 @@ def test_available_tracks():
|
|||
|
||||
# === Command line ===
|
||||
|
||||
def test_main_downloads_auto_original(tmp_path, monkeypatch, capsys):
|
||||
def test_main_downloads_auto_original(fake_yt_dlp, tmp_path, monkeypatch, capsys):
|
||||
run = fake_yt_dlp(AUTO_ONLY)
|
||||
monkeypatch.setattr(yt.subprocess, "run", run)
|
||||
run_main(monkeypatch, "-u", URL, "-n", "Rede", "-d", tmp_path / "neu")
|
||||
|
|
@ -93,7 +67,7 @@ def test_main_downloads_auto_original(tmp_path, monkeypatch, capsys):
|
|||
assert "vtt2txt.py -i" in out
|
||||
|
||||
|
||||
def test_main_prefers_manual_and_defaults_to_video_id(tmp_path, monkeypatch):
|
||||
def test_main_prefers_manual_and_defaults_to_video_id(fake_yt_dlp, tmp_path, monkeypatch):
|
||||
info = dict(AUTO_ONLY, subtitles={"de": []})
|
||||
run = fake_yt_dlp(info)
|
||||
monkeypatch.setattr(yt.subprocess, "run", run)
|
||||
|
|
@ -103,7 +77,7 @@ def test_main_prefers_manual_and_defaults_to_video_id(tmp_path, monkeypatch):
|
|||
assert "--write-subs" in run.calls[1]
|
||||
|
||||
|
||||
def test_main_no_matching_track(tmp_path, monkeypatch):
|
||||
def test_main_no_matching_track(fake_yt_dlp, tmp_path, monkeypatch):
|
||||
monkeypatch.setattr(yt.subprocess, "run", fake_yt_dlp(AUTO_ONLY))
|
||||
with pytest.raises(SystemExit, match="Automatisch \\(Originalsprache\\): de"):
|
||||
run_main(monkeypatch, "-u", URL, "-l", "en", "-d", tmp_path)
|
||||
|
|
@ -122,7 +96,7 @@ def test_main_info_error(tmp_path, monkeypatch):
|
|||
({"fail_download": True}, "HTTP Error 429"),
|
||||
({"write": False}, "keine Datei"),
|
||||
])
|
||||
def test_main_download_errors(tmp_path, monkeypatch, kwargs, message):
|
||||
def test_main_download_errors(fake_yt_dlp, tmp_path, monkeypatch, kwargs, message):
|
||||
monkeypatch.setattr(yt.subprocess, "run", fake_yt_dlp(AUTO_ONLY, **kwargs))
|
||||
with pytest.raises(SystemExit, match=message):
|
||||
run_main(monkeypatch, "-u", URL, "-d", tmp_path)
|
||||
|
|
|
|||
Loading…
Reference in a new issue