"""Tests for tmdb.py against a mocked httpx transport — no live network in CI.""" import httpx import pytest from meshbay_node.tmdb import TmdbClient class FakeRoster: def __init__(self, enabled: bool = True, token: str | None = "fake-token", language: str | None = None): self._enabled = enabled self._token = token self._language = language async def tmdb_config(self): return self._enabled, self._token, self._language def _handler(response_map): def handle(request: httpx.Request) -> httpx.Response: path = request.url.path for prefix, body in response_map.items(): if path.endswith(prefix): return httpx.Response(200, json=body) return httpx.Response(404, json={"results": []}) return handle @pytest.mark.asyncio async def test_search_movie_returns_top_result_and_confidence(): body = {"results": [{"id": 42, "title": "The Great Adventure", "release_date": "2015-01-01"}]} client = TmdbClient( roster=FakeRoster(), transport=httpx.MockTransport(_handler({"search/movie": body})), ) result, ratio = await client.search_movie("The Great Adventure", 2015) assert result is not None assert result["id"] == 42 assert ratio > 0.9 await client.close() @pytest.mark.asyncio async def test_search_tv_returns_top_result(): body = {"results": [{"id": 7, "name": "Some Show"}]} client = TmdbClient( roster=FakeRoster(), transport=httpx.MockTransport(_handler({"search/tv": body})), ) result, ratio = await client.search_tv("Some Show") assert result is not None and result["id"] == 7 assert ratio > 0.9 await client.close() @pytest.mark.asyncio async def test_configured_language_is_sent_to_tmdb(): captured = {} def handle(request: httpx.Request) -> httpx.Response: captured["language"] = request.url.params.get("language") return httpx.Response(200, json={"results": []}) client = TmdbClient( roster=FakeRoster(language="fr-FR"), transport=httpx.MockTransport(handle), ) await client.search_movie("Anything") assert captured["language"] == "fr-FR" await client.close() @pytest.mark.asyncio async def test_no_language_configured_omits_the_param(): captured = {} def handle(request: httpx.Request) -> httpx.Response: captured["has_language"] = "language" in request.url.params return httpx.Response(200, json={"results": []}) client = TmdbClient( roster=FakeRoster(language=None), transport=httpx.MockTransport(handle), ) await client.search_movie("Anything") assert captured["has_language"] is False await client.close() @pytest.mark.asyncio async def test_no_results_returns_none_and_zero_confidence(): client = TmdbClient( roster=FakeRoster(), transport=httpx.MockTransport(_handler({"search/movie": {"results": []}})), ) result, ratio = await client.search_movie("Nonexistent Obscure Title") assert result is None assert ratio == 0.0 await client.close() @pytest.mark.asyncio async def test_disabled_via_roster_setting_makes_no_request(): calls = [] def handle(request: httpx.Request) -> httpx.Response: calls.append(request) return httpx.Response(200, json={"results": []}) client = TmdbClient( roster=FakeRoster(enabled=False), transport=httpx.MockTransport(handle), ) result, ratio = await client.search_movie("Anything") assert result is None assert calls == [] # confirms the disabled check short-circuits before any request await client.close() @pytest.mark.asyncio async def test_no_token_resolvable_makes_no_request(monkeypatch): monkeypatch.delenv("MESHBAY_TMDB_DEFAULT_TOKEN", raising=False) calls = [] def handle(request: httpx.Request) -> httpx.Response: calls.append(request) return httpx.Response(200, json={"results": []}) client = TmdbClient( roster=FakeRoster(enabled=True, token=None), transport=httpx.MockTransport(handle), ) result, ratio = await client.search_movie("Anything") assert result is None assert calls == [] await client.close() @pytest.mark.asyncio async def test_http_error_returns_none_gracefully(): def handle(request: httpx.Request) -> httpx.Response: return httpx.Response(500, json={"status_message": "server error"}) client = TmdbClient( roster=FakeRoster(), transport=httpx.MockTransport(handle), ) result, ratio = await client.search_movie("Anything") assert result is None assert ratio == 0.0 await client.close() @pytest.mark.asyncio async def test_poster_url_builds_full_url(): assert TmdbClient.poster_url("/abc123.jpg") == "https://image.tmdb.org/t/p/w500/abc123.jpg" assert TmdbClient.poster_url(None) is None