from __future__ import annotations import unittest from chart_data_provider import ChartDataError, EastmoneyChartClient from server import DashboardService class FakeChartClient(EastmoneyChartClient): def __init__(self) -> None: super().__init__(cache_ttl_seconds=20) self.requests: list[tuple[str, dict[str, str]]] = [] def _request_json(self, url, params, referer): self.requests.append((url, params)) if "trends2" in url: return { "data": { "code": params["secid"].split(".", 1)[1], "name": "测试行情", "preClose": 10.0, "trends": [ "2026-07-24 09:30,10.10,10.20,10.30,10.00,100,1020.00,10.200", "2026-07-24 09:31,10.20,10.15,10.25,10.10,80,812.00,10.178", ], } } return { "data": { "diff": [ {"f12": "BK0474", "f14": "保险Ⅱ"}, {"f12": "BK1040", "f14": "中药Ⅱ"}, ] } } class ChartDataProviderTests(unittest.TestCase): def setUp(self) -> None: EastmoneyChartClient._cache.clear() EastmoneyChartClient._board_catalog.clear() EastmoneyChartClient._board_catalog_at = 0 self.client = FakeChartClient() def test_stock_intraday_maps_market_and_parses_points(self): payload = self.client.stock_intraday("601318") self.assertEqual(self.client.requests[0][1]["secid"], "1.601318") self.assertEqual(payload["trade_date"], "2026-07-24") self.assertEqual(payload["points"][0]["time"], "09:30") self.assertEqual(payload["points"][0]["average"], 10.2) def test_short_cache_avoids_duplicate_hover_requests(self): self.client.stock_intraday("002141") self.client.stock_intraday("002141") trend_requests = [item for item in self.client.requests if "trends2" in item[0]] self.assertEqual(len(trend_requests), 1) def test_index_and_board_use_the_same_chart_shape(self): index = self.client.index_intraday("000001.SH") board = self.client.board_intraday("BK0474") self.assertEqual(index["points"][1]["close"], 10.15) self.assertEqual(board["points"][1]["volume"], 80.0) secids = [params["secid"] for url, params in self.client.requests if "trends2" in url] self.assertIn("1.000001", secids) self.assertIn("90.BK0474", secids) def test_invalid_identifier_is_rejected(self): with self.assertRaises(ChartDataError): self.client.stock_intraday("abc") class ChartServiceStub: @staticmethod def _payload(code: str, name: str): return { "code": code, "name": name, "trade_date": "2026-07-24", "previous_close": 10, "points": [{"date": "2026-07-24", "time": "09:30", "close": 10.1}], } def stock_intraday(self, code): return self._payload(code, "测试股票") def index_intraday(self, identifier): return self._payload(identifier, "上证指数") def board_intraday(self, identifier, name=""): return self._payload("BK0474", name) class ChartDirectoryStub: @staticmethod def get_data_snapshot(kind, cache_key): if (kind, cache_key) != ("search_directory", "ths"): return None return { "schema_version": 2, "items": [ {"id": "881107.TI", "name": "保险", "type": "sector"}, {"id": "885728.TI", "name": "人工智能", "type": "theme"}, ], } class IntradayChartServiceTests(unittest.TestCase): def setUp(self): self.service = DashboardService.__new__(DashboardService) self.service.chart_data = ChartServiceStub() self.service.database = ChartDirectoryStub() def test_stock_index_sector_and_theme_share_display_only_contract(self): cases = ( ("stock", "601318"), ("index", "000001.SH"), ("sector", "881107.TI"), ("theme", "885728.TI"), ) for entity_type, identifier in cases: with self.subTest(entity_type=entity_type): payload = self.service.get_intraday_chart(entity_type, identifier) self.assertEqual(payload["entity"]["type"], entity_type) self.assertEqual(payload["meta"]["trade_date"], "2026-07-24") self.assertEqual(len(payload["points"]), 1) self.assertNotIn("source", payload["meta"]) if __name__ == "__main__": unittest.main()