mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-12 12:05:07 +00:00
Each keeps one kind of track inside its track type. A run of more than one title skips a title that has no such track. The REST API rejects a non-boolean value for a boolean dl param, and the DASH parser reads audio description from Role elements.
74 lines
3.4 KiB
Python
74 lines
3.4 KiB
Python
"""The dl.result call site of missing_required_langs, and inputs the unit tests skip.
|
|
|
|
The gate in dl.result is not extractable without executing the whole download loop, so
|
|
its wiring is pinned the same way test_required_langs pins download_manager: against the
|
|
source. The value inputs cover what the helper's own tests leave out — real tracks carry
|
|
langcodes.Language objects, not strings.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import inspect
|
|
|
|
from langcodes import Language
|
|
|
|
from unshackle.commands.dl import dl
|
|
from unshackle.core.utilities import missing_required_langs
|
|
|
|
|
|
def test_language_objects_satisfy_a_requirement():
|
|
# track.language is a langcodes.Language, never a str, at the real call site
|
|
assert missing_required_langs(["en"], [Language.get("en")]) == []
|
|
assert missing_required_langs(["en"], [Language.get("en-US")]) == []
|
|
assert missing_required_langs(["en"], [Language.get("fr")]) == ["en"]
|
|
|
|
|
|
def test_orig_accepts_a_language_object_title_language():
|
|
# title.language is a langcodes.Language at the call site, never a str
|
|
assert missing_required_langs(["orig"], ["ja"], Language.get("ja")) == []
|
|
assert missing_required_langs(["orig"], ["en"], Language.get("ja")) == ["ja"]
|
|
|
|
|
|
def test_requirement_checks_the_catalogue_not_the_selection():
|
|
# -l best,-fr --require-audio en: the gate answers "does en exist", so the
|
|
# exclusion of fr from the *selection* must not make en count as missing
|
|
assert missing_required_langs(["en"], ["en", "ko", "ja", "fr"]) == []
|
|
# requiring a language the selection excludes is still satisfied by the catalogue
|
|
assert missing_required_langs(["fr"], ["en", "ko", "ja", "fr"]) == []
|
|
|
|
|
|
class TestGateWiring:
|
|
"""Pin the dl.result gate's shape; a silent rewire is otherwise invisible to tests."""
|
|
|
|
source = inspect.getsource(dl.result)
|
|
|
|
def test_gate_is_disabled_with_the_track_kind(self):
|
|
# --no-audio / -V must not fail on a require_audio the download cannot honour
|
|
assert "require_audio if keep_audio else []" in self.source
|
|
assert "require_video if keep_videos else []" in self.source
|
|
|
|
def test_gate_counts_audio_embedded_in_kept_video(self):
|
|
assert "embedded_audio_langs(title.tracks.videos, keep_videos and not audio_description_only)" in self.source
|
|
|
|
def test_gate_honours_exact_lang(self):
|
|
assert "missing_required_langs(required, available, title.language, exact=exact_lang)" in self.source
|
|
|
|
def test_gate_reads_tracks_before_the_keep_flags_empty_them(self):
|
|
# the availability lists must be built before `if not keep_videos:` clears
|
|
# title.tracks.videos, or embedded audio could never satisfy a requirement
|
|
gate = self.source.index("missing_required_langs(required")
|
|
reset = self.source.index("if not keep_videos:")
|
|
assert gate < reset
|
|
|
|
def test_require_and_exclude_clash_is_rejected_per_flag(self):
|
|
# --require-audio en with -l all,-en can never be satisfied as the user
|
|
# meant it, so it must die at parse time, against each flag's own
|
|
# exclusion list (-vl/-al cascade from -l only when unset)
|
|
assert "cannot be required and excluded at the same time" in self.source
|
|
for pair in (
|
|
'("--require-audio", require_audio, audio_excl)',
|
|
'("--require-video", require_video, video_excl)',
|
|
'("--require-subs", require_subs, s_lang_excl)',
|
|
):
|
|
assert pair in self.source
|