18267d0165
Mirror the MediaProber / FilesystemScanner pattern for language lookup: - New Protocol `LanguageRepository` in alfred.domain.shared.ports covering from_iso, from_any, all, __contains__, __len__ — the surface previously coupled to the concrete LanguageRegistry. - SubtitleKnowledgeBase types its `language_registry` parameter against the Protocol; the concrete LanguageRegistry stays in infrastructure as the YAML-backed adapter and remains the default when no repository is injected. - New unit tests in tests/infrastructure/test_language_registry.py cover the adapter surface (from_iso, from_any, membership, case-insensitivity, non-string inputs). Behaviour is unchanged for existing callers. The split opens the door to in-memory fakes in future tests without loading the full ISO 639 YAML.
83 lines
2.7 KiB
Python
83 lines
2.7 KiB
Python
"""Tests for ``LanguageRegistry`` — the YAML-backed adapter for the
|
|
:class:`alfred.domain.shared.ports.LanguageRepository` port.
|
|
|
|
The port is structural (Protocol), so the assertion that the adapter
|
|
satisfies it is a static one — we exercise the public surface here and
|
|
let mypy / runtime polymorphism do the rest.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from alfred.domain.shared.ports import LanguageRepository
|
|
from alfred.domain.shared.value_objects import Language
|
|
from alfred.infrastructure.knowledge.language_registry import LanguageRegistry
|
|
|
|
|
|
def _registry() -> LanguageRepository:
|
|
"""Return a fresh registry typed as the port — proves structural fit."""
|
|
return LanguageRegistry()
|
|
|
|
|
|
class TestPortSurface:
|
|
def test_satisfies_protocol(self):
|
|
# If LanguageRegistry diverged from LanguageRepository, the annotation
|
|
# below would already be wrong at type-check time; at runtime, this
|
|
# just confirms the methods exist.
|
|
reg: LanguageRepository = LanguageRegistry()
|
|
assert hasattr(reg, "from_iso")
|
|
assert hasattr(reg, "from_any")
|
|
assert hasattr(reg, "all")
|
|
|
|
def test_len_reflects_loaded_entries(self):
|
|
reg = _registry()
|
|
# The builtin YAML ships dozens of languages — exact count drifts
|
|
# with knowledge updates, so just sanity-check it's non-empty.
|
|
assert len(reg) > 0
|
|
|
|
|
|
class TestFromIso:
|
|
def test_known_iso_returns_language(self):
|
|
reg = _registry()
|
|
fre = reg.from_iso("fre")
|
|
assert isinstance(fre, Language)
|
|
assert fre.iso == "fre"
|
|
|
|
def test_case_insensitive(self):
|
|
reg = _registry()
|
|
assert reg.from_iso("FRE") == reg.from_iso("fre")
|
|
|
|
def test_unknown_iso_returns_none(self):
|
|
assert _registry().from_iso("zzz") is None
|
|
|
|
def test_non_string_returns_none(self):
|
|
assert _registry().from_iso(None) is None # type: ignore[arg-type]
|
|
|
|
|
|
class TestFromAny:
|
|
def test_english_name(self):
|
|
reg = _registry()
|
|
lang = reg.from_any("French")
|
|
assert lang is not None
|
|
assert lang.iso == "fre"
|
|
|
|
def test_iso_639_1_alias(self):
|
|
# "fr" is the 639-1 form, registered as an alias.
|
|
reg = _registry()
|
|
lang = reg.from_any("fr")
|
|
assert lang is not None
|
|
assert lang.iso == "fre"
|
|
|
|
def test_unknown_returns_none(self):
|
|
assert _registry().from_any("vostfr") is None
|
|
|
|
def test_non_string_returns_none(self):
|
|
assert _registry().from_any(123) is None # type: ignore[arg-type]
|
|
|
|
|
|
class TestMembership:
|
|
def test_contains_known(self):
|
|
assert "english" in _registry()
|
|
|
|
def test_does_not_contain_unknown(self):
|
|
assert "klingon" not in _registry()
|