Files
unshackle/tests/core/test_metadata_id_validation.py
T
imSp4rky ebb4e74318 feat(metadata)!: authoritative id resolver and keyless imdb provider
Supplied IDs resolve directly via a shared resolve_by_ids and never fall back to title search; metadata_providers gains per-kind ordering and a disable_metadata switch stops all automatic lookups while explicit IDs keep working.
BREAKING: --tmdb/--imdb/--tvdb are now mutually exclusive and require a usable provider; --enrich also overwrites original language; the imdbapi provider and imdb_api_enabled are replaced by a keyless imdb provider.
2026-08-11 15:07:24 -06:00

115 lines
4.2 KiB
Python

"""Input validation for the --tmdb / --imdb / --tvdb flags."""
from __future__ import annotations
import click
import pytest
from unshackle.commands.dl import validate_metadata_ids
from unshackle.core.api.handlers import validate_download_parameters
from unshackle.core.config import config
@pytest.fixture(autouse=True)
def _default_order(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr(config, "metadata_providers", [])
def _with_keys(monkeypatch: pytest.MonkeyPatch, **keys: str) -> None:
for name in ("tmdb_api_key", "tvdb_api_key", "omdb_api_key", "simkl_client_id"):
monkeypatch.setattr(config, name, keys.get(name, ""))
# ---------- one ID at a time ----------
@pytest.mark.parametrize(
("tmdb", "imdb", "tvdb"),
[(27205, "tt1375666", None), (27205, None, 73871), (None, "tt1375666", 73871), (27205, "tt1375666", 73871)],
)
def test_two_ids_are_refused(tmdb: int | None, imdb: str | None, tvdb: int | None) -> None:
with pytest.raises(click.UsageError) as exc:
validate_metadata_ids(tmdb, imdb, tvdb)
assert "cannot be used together" in str(exc.value)
def test_no_ids_is_fine() -> None:
assert validate_metadata_ids(None, None, None) is None
def test_imdb_alone_passes_on_the_keyless_provider(monkeypatch: pytest.MonkeyPatch) -> None:
_with_keys(monkeypatch)
assert validate_metadata_ids(None, "tt1375666", None) is None
# ---------- the ID must have a provider that can resolve it ----------
def test_tmdb_without_its_key_names_the_key(monkeypatch: pytest.MonkeyPatch) -> None:
_with_keys(monkeypatch)
with pytest.raises(click.UsageError) as exc:
validate_metadata_ids(27205, None, None)
assert "--tmdb" in str(exc.value) and "tmdb_api_key" in str(exc.value)
def test_tvdb_without_its_key_names_the_key(monkeypatch: pytest.MonkeyPatch) -> None:
_with_keys(monkeypatch)
with pytest.raises(click.UsageError) as exc:
validate_metadata_ids(None, None, 73871)
assert "--tvdb" in str(exc.value) and "tvdb_api_key" in str(exc.value)
def test_tmdb_with_its_key_passes(monkeypatch: pytest.MonkeyPatch) -> None:
_with_keys(monkeypatch, tmdb_api_key="k")
assert validate_metadata_ids(27205, None, None) is None
def test_a_provider_filtered_out_of_the_order_points_at_the_config(monkeypatch: pytest.MonkeyPatch) -> None:
_with_keys(monkeypatch, tmdb_api_key="k")
monkeypatch.setattr(config, "metadata_providers", ["imdb", "omdb"])
with pytest.raises(click.UsageError) as exc:
validate_metadata_ids(27205, None, None)
assert "metadata_providers" in str(exc.value)
def test_imdb_is_unresolvable_when_the_order_drops_both_of_its_providers(monkeypatch: pytest.MonkeyPatch) -> None:
_with_keys(monkeypatch)
monkeypatch.setattr(config, "metadata_providers", ["tmdb", "tvdb"])
with pytest.raises(click.UsageError) as exc:
validate_metadata_ids(None, "tt1375666", None)
assert "metadata_providers" in str(exc.value)
assert "imdb" in str(exc.value) and "omdb" in str(exc.value)
def test_one_kind_keeping_the_provider_is_enough(monkeypatch: pytest.MonkeyPatch) -> None:
"""A per-kind order can drop tvdb for movies and keep it for tv, so this must not error."""
_with_keys(monkeypatch, tvdb_api_key="k")
monkeypatch.setattr(config, "metadata_providers", {"tv": ["tvdb"], "movie": ["tmdb"]})
assert validate_metadata_ids(None, None, 73871) is None
# ---------- the REST path rejects the same combinations ----------
@pytest.mark.parametrize(
"payload",
[
{"tmdb_id": 27205, "imdb_id": "tt1375666"},
{"tmdb_id": 27205, "tvdb_id": 73871},
{"imdb_id": "tt1375666", "tvdb_id": 73871},
],
)
def test_api_refuses_two_ids(payload: dict) -> None:
err = validate_download_parameters(payload)
assert err and "multiple external IDs" in err
@pytest.mark.parametrize("payload", [{"tmdb_id": 27205}, {"imdb_id": "tt1375666"}, {"tvdb_id": 73871}, {}])
def test_api_accepts_one_id(payload: dict) -> None:
assert validate_download_parameters(payload) is None
def test_api_still_reports_a_malformed_id_first() -> None:
err = validate_download_parameters({"tmdb_id": "12345", "imdb_id": "tt1"})
assert err and "positive integer" in err