"""Market lookup tools and pure aggregation helpers.""" import asyncio import pytest from familiar import hubs, market from familiar.server import mcp from conftest import route JITA_STATION = 60003760 JITA_REGION = 10000002 def _orders(): return [ # Sells at Jita { "is_buy_order": False, "location_id": JITA_STATION, "price": 5.10, "volume_remain": 100, "range": "station", }, { "is_buy_order": False, "location_id": JITA_STATION, "price": 5.05, "volume_remain": 200, "range": "station", }, # Buy at Jita { "is_buy_order": True, "location_id": JITA_STATION, "price": 4.90, "volume_remain": 300, "range": "region", }, # Order at a different station should be ignored { "is_buy_order": False, "location_id": 999, "price": 1.0, "volume_remain": 1, "range": "station", }, ] def test_summarize_orders_picks_best_and_ignores_other_stations(): s = market.summarize_orders(_orders(), JITA_STATION) assert s["best_sell"] == 5.05 assert s["best_buy"] == 4.90 assert s["spread"] == 0.15 assert s["sell_orders"] == 2 assert s["volume_on_sell"] == 300 def test_summarize_orders_handles_empty(): s = market.summarize_orders([], JITA_STATION) assert s["best_sell"] is None assert s["spread"] is None def test_top_orders_sorts_per_side(): sells = market.top_orders(_orders(), JITA_STATION, "sell", 10) assert [o["price"] for o in sells] == [5.05, 5.10] buys = market.top_orders(_orders(), JITA_STATION, "buy", 10) assert [o["price"] for o in buys] == [4.90] def test_get_market_price(mock_esi): fixtures = { "/universe/ids/": {"inventory_types": [{"id": 34, "name": "Tritanium"}]}, f"/markets/{JITA_REGION}/orders/": _orders(), } mock_esi(lambda req: route(req, fixtures)) result = asyncio.run(market.get_market_price("Tritanium", hub="Jita")) assert result["type_id"] == 34 assert result["hub"] == "Jita" assert result["best_sell"] == 5.05 def test_get_market_orders_side_parsing(mock_esi): fixtures = {f"/markets/{JITA_REGION}/orders/": _orders()} mock_esi(lambda req: route(req, fixtures)) result = asyncio.run(market.get_market_orders(34, hub="Jita", side="buy", limit=5)) assert result["side"] == "buy" assert result["orders"][0]["price"] == 4.90 def test_compare_hubs_across_all_regions(mock_esi): # Every region returns the same order book; cheapest sell is the same price # everywhere, so the first hub (Jita) wins the tie. def handler(req): return route( req, { "/orders/": _orders(), "/universe/ids/": {"inventory_types": [{"id": 34, "name": "Tritanium"}]}, }, ) mock_esi(handler) result = asyncio.run(market.compare_hubs("Tritanium")) assert len(result["hubs"]) == len(hubs.HUBS) assert result["cheapest_sell_hub"] == "Jita" def test_list_hubs(): result = asyncio.run(market.list_hubs()) names = {h["name"] for h in result} assert {"Jita", "Amarr", "Dodixie", "Rens", "Hek"} == names def test_resolve_hub_unknown_raises(): with pytest.raises(ValueError): hubs.resolve_hub("Atlantis") def test_resolve_hub_defaults_to_jita(): assert hubs.resolve_hub(None).name == "Jita" def test_market_tools_are_registered(): tools = {t.name for t in asyncio.run(mcp.list_tools())} assert {"list_hubs", "get_market_price", "get_market_orders", "compare_hubs"} <= tools