"""Tests for /api/v1/preferences/card-modes endpoints.""" import pytest from ledgrab.config import get_config @pytest.fixture(scope="module") def client(): """TestClient with auth header read at fixture-build time. Mirrors test_preferences_api.py — the auth key is resolved here so any singleton mutation during pytest collection cannot leave us with a stale Bearer header. """ from fastapi.testclient import TestClient from ledgrab.main import app api_key = next(iter(get_config().auth.api_keys.values()), "") with TestClient(app, raise_server_exceptions=False) as c: if api_key: c.headers["Authorization"] = f"Bearer {api_key}" yield c def _prefs(surfaces: dict[str, str] | None = None) -> dict: return {"version": 1, "surfaces": surfaces or {}} def test_get_default_empty(client): """When nothing is saved, GET returns {}.""" client.delete("/api/v1/preferences/card-modes") resp = client.get("/api/v1/preferences/card-modes") assert resp.status_code == 200 assert resp.json() == {} def test_put_then_get_round_trip(client): """PUT a prefs object, GET it back verbatim.""" body = _prefs({"led-devices": "dense", "led-targets": "comfortable"}) put = client.put("/api/v1/preferences/card-modes", json=body) assert put.status_code == 200 assert put.json() == {"ok": True} got = client.get("/api/v1/preferences/card-modes") assert got.status_code == 200 assert got.json() == body def test_put_rejects_missing_version(client): """Body without numeric version is rejected with 422.""" resp = client.put( "/api/v1/preferences/card-modes", json={"surfaces": {"led-devices": "dense"}}, ) assert resp.status_code == 422 def test_put_rejects_invalid_mode(client): """A mode value outside the allowed set is rejected with 422.""" resp = client.put( "/api/v1/preferences/card-modes", json=_prefs({"led-devices": "extreme"}), ) assert resp.status_code == 422 def test_put_rejects_non_dict_surfaces(client): """`surfaces` must be an object, not an array or string.""" resp = client.put( "/api/v1/preferences/card-modes", json={"version": 1, "surfaces": ["led-devices", "dense"]}, ) assert resp.status_code == 422 def test_put_accepts_empty_surfaces(client): """An empty surfaces map is a valid (no-override) state.""" resp = client.put("/api/v1/preferences/card-modes", json=_prefs({})) assert resp.status_code == 200 def test_put_accepts_unknown_surface_keys(client): """Surface keys are an open registry — any non-empty string is OK.""" body = _prefs( { "led-devices": "compact", "automations": "dense", "weather-sources": "comfortable", "future-surface-v2": "compact", } ) resp = client.put("/api/v1/preferences/card-modes", json=body) assert resp.status_code == 200 got = client.get("/api/v1/preferences/card-modes").json() assert got["surfaces"]["future-surface-v2"] == "compact" def test_put_accepts_row_mode(client): """`row` is a valid mode (added alongside the original three).""" body = _prefs({"led-devices": "row"}) resp = client.put("/api/v1/preferences/card-modes", json=body) assert resp.status_code == 200 got = client.get("/api/v1/preferences/card-modes").json() assert got["surfaces"]["led-devices"] == "row" def test_delete_clears(client): """DELETE wipes saved prefs so the next GET returns empty.""" client.put( "/api/v1/preferences/card-modes", json=_prefs({"led-devices": "dense"}), ) deleted = client.delete("/api/v1/preferences/card-modes") assert deleted.status_code == 200 after = client.get("/api/v1/preferences/card-modes") assert after.status_code == 200 assert after.json() == {}