"""Authenticated account tools (auth mocked, ESI mocked).""" import asyncio import httpx import pytest from familiar import account, auth from familiar.server import mcp from conftest import route @pytest.fixture def fake_auth(monkeypatch): async def _stub(): return "fake-token", 99 monkeypatch.setattr(auth, "get_auth", _stub) return 99 def test_get_wallet(mock_esi, fake_auth): mock_esi(lambda req: httpx.Response(200, json=1234567.89)) result = asyncio.run(account.get_wallet()) assert result["character_id"] == 99 assert result["balance"] == 1234567.89 def test_get_skills_summarizes(mock_esi, fake_auth): body = {"total_sp": 5_000_000, "unallocated_sp": 10_000, "skills": [{}, {}, {}]} mock_esi(lambda req: route(req, {"/skills/": body})) result = asyncio.run(account.get_skills()) assert result["total_sp"] == 5_000_000 assert result["skills_trained"] == 3 def test_get_skill_queue_limits(mock_esi, fake_auth): queue = [ {"skill_id": i, "finished_level": 5, "queue_position": i, "finish_date": "2026"} for i in range(5) ] mock_esi(lambda req: route(req, {"/skillqueue/": queue})) result = asyncio.run(account.get_skill_queue(limit=2)) assert result["in_queue"] == 5 assert len(result["upcoming"]) == 2 def test_get_location_merges_endpoints(mock_esi, fake_auth): fixtures = { "/location/": {"solar_system_id": 30000142, "station_id": 60003760}, "/ship/": {"ship_type_id": 670, "ship_name": "My Capsule"}, "/online/": {"online": True, "last_login": "2026-06-27T00:00:00Z"}, } mock_esi(lambda req: route(req, fixtures)) result = asyncio.run(account.get_location()) assert result["solar_system_id"] == 30000142 assert result["ship_name"] == "My Capsule" assert result["online"] is True def test_get_clones(mock_esi, fake_auth): fixtures = { "/clones/": {"home_location": {"location_id": 60003760}, "jump_clones": [{}, {}]}, "/implants/": [10000, 10001], } mock_esi(lambda req: route(req, fixtures)) result = asyncio.run(account.get_clones()) assert result["jump_clones"] == 2 assert result["active_implants"] == [10000, 10001] def test_get_assets_paginates(mock_esi, fake_auth): # Two pages of assets; the client should follow X-Pages and concatenate. def handler(req): page = req.url.params.get("page", "1") if page == "1": return httpx.Response( 200, json=[{"type_id": 34, "quantity": 1, "location_id": 1}], headers={"X-Pages": "2"}, ) return httpx.Response( 200, json=[{"type_id": 35, "quantity": 2, "location_id": 1}], headers={"X-Pages": "2"}, ) mock_esi(handler) result = asyncio.run(account.get_assets(limit=20)) assert result["total_stacks"] == 2 assert {a["type_id"] for a in result["sample"]} == {34, 35} def test_account_status_delegates(monkeypatch): monkeypatch.setattr(auth, "status", lambda: {"authenticated": True, "character_id": 1}) result = asyncio.run(account.account_status()) assert result["authenticated"] is True def test_account_tools_registered(): tools = {t.name for t in asyncio.run(mcp.list_tools())} assert {"get_wallet", "get_skills", "get_location", "get_assets", "account_status"} <= tools