mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-12 20:15:10 +00:00
172 lines
6.8 KiB
Python
172 lines
6.8 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, ""))
|
|
|
|
|
|
@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
|
|
|
|
|
|
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
|
|
|
|
|
|
@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
|
|
|
|
|
|
@pytest.mark.parametrize("value", [21, "21", "mal:21"])
|
|
def test_anilist_alone_passes_without_any_key(monkeypatch: pytest.MonkeyPatch, value: object) -> None:
|
|
with_keys(monkeypatch)
|
|
assert validate_metadata_ids(None, None, None, value) is None
|
|
|
|
|
|
def test_anilist_pairs_with_one_other_id(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
with_keys(monkeypatch)
|
|
assert validate_metadata_ids(None, "tt1375666", None, 21) is None
|
|
|
|
|
|
def test_anilist_does_not_excuse_two_western_ids(monkeypatch: pytest.MonkeyPatch) -> None:
|
|
with_keys(monkeypatch)
|
|
with pytest.raises(click.UsageError) as exc:
|
|
validate_metadata_ids(27205, "tt1375666", None, 21)
|
|
assert "cannot be used together" in str(exc.value)
|
|
|
|
|
|
@pytest.mark.parametrize("value", ["tt1375666", "anilist:21", "mal:", "abc", "-3"])
|
|
def test_a_malformed_anilist_value_is_refused(monkeypatch: pytest.MonkeyPatch, value: str) -> None:
|
|
with_keys(monkeypatch)
|
|
with pytest.raises(click.UsageError) as exc:
|
|
validate_metadata_ids(None, None, None, value)
|
|
assert "--anilist" in str(exc.value)
|
|
|
|
|
|
@pytest.mark.parametrize("payload", [{"anilist_id": 21}, {"anilist_id": "mal:21"}, {"anilist_id": "21"}])
|
|
def test_api_accepts_an_anilist_id(payload: dict) -> None:
|
|
assert validate_download_parameters(payload) is None
|
|
|
|
|
|
def test_api_accepts_anilist_alongside_one_western_id() -> None:
|
|
assert validate_download_parameters({"imdb_id": "tt1375666", "anilist_id": 21}) is None
|
|
|
|
|
|
def test_api_still_refuses_two_western_ids_with_anilist() -> None:
|
|
err = validate_download_parameters({"tmdb_id": 27205, "imdb_id": "tt1375666", "anilist_id": 21})
|
|
assert err and "multiple external IDs" in err
|
|
|
|
|
|
@pytest.mark.parametrize("value", [0, -3, True, "mal:", "tt1375666", "anilist:21", 1.5])
|
|
def test_api_refuses_a_malformed_anilist_id(value: object) -> None:
|
|
err = validate_download_parameters({"anilist_id": value})
|
|
assert err and "anilist_id" in err
|
|
|
|
|
|
@pytest.mark.parametrize("value", ["0", "mal:0", "²", "21.5"])
|
|
def test_a_non_positive_or_non_decimal_anilist_value_is_refused(monkeypatch: pytest.MonkeyPatch, value: str) -> None:
|
|
with_keys(monkeypatch)
|
|
with pytest.raises(click.UsageError) as exc:
|
|
validate_metadata_ids(None, None, None, value)
|
|
assert "--anilist" in str(exc.value)
|
|
|
|
|
|
@pytest.mark.parametrize("payload", [{"anilist_id": "MAL:21"}, {"anilist_id": "007"}, {"anilist_id": " 21 "}])
|
|
def test_api_accepts_what_the_cli_accepts(payload: dict) -> None:
|
|
"""Both surfaces share parse_anilist_ref, so their accept sets cannot drift."""
|
|
assert validate_download_parameters(payload) is None
|
|
|
|
|
|
@pytest.mark.parametrize("value", ["0", "mal:0", "²"])
|
|
def test_api_refuses_what_the_cli_refuses(value: str) -> None:
|
|
err = validate_download_parameters({"anilist_id": value})
|
|
assert err and "anilist_id" in err
|