"""ground_link_test.py —— 地面坐标注入通道单元测试。 覆盖:parse_payload 解析(合法/缺字段/非法 JSON/非对象/类型错误)、 is_valid 新鲜度判定(未注入/新鲜/超龄边界)。 """ import pytest from pod_bridge.ground_link import GroundInjectConfig, GroundLink, GroundTarget # --- parse_payload ---------------------------------------------------------- def test_parse_valid_payload(): t = GroundLink.parse_payload( b'{"lat": 39.9042, "lon": 116.4074, "alt": 50.0}') assert t is not None assert t.latitude_deg == pytest.approx(39.9042) assert t.longitude_deg == pytest.approx(116.4074) assert t.abs_alt_m == pytest.approx(50.0) assert t.time_ms == 0 # 打戳由接收方(run)负责 def test_parse_default_alt_is_zero(): t = GroundLink.parse_payload(b'{"lat": 1.0, "lon": 2.0}') assert t is not None assert t.abs_alt_m == 0.0 def test_parse_missing_lat_returns_none(): assert GroundLink.parse_payload(b'{"lon": 2.0}') is None def test_parse_missing_lon_returns_none(): assert GroundLink.parse_payload(b'{"lat": 1.0}') is None def test_parse_invalid_json_returns_none(): assert GroundLink.parse_payload(b'not json') is None def test_parse_non_object_returns_none(): assert GroundLink.parse_payload(b'[1, 2, 3]') is None def test_parse_string_coords_returns_none(): assert GroundLink.parse_payload(b'{"lat": "x", "lon": 2.0}') is None def test_parse_bool_coords_returns_none(): # True 是 bool 不是数值 → 拒绝 assert GroundLink.parse_payload(b'{"lat": true, "lon": 2.0}') is None def test_parse_ignores_ts_field(): """ts 字段仅诊断,不参与解析(新鲜度用本地接收时刻)。""" t = GroundLink.parse_payload(b'{"lat": 1.0, "lon": 2.0, "ts": 999}') assert t is not None assert t.latitude_deg == pytest.approx(1.0) # --- is_valid --------------------------------------------------------------- def _link(timeout_ms=5000): return GroundLink(GroundInjectConfig(timeout_ms=timeout_ms), now_ms_fn=lambda: 0) def _inject(link, time_ms): link._target = GroundTarget(latitude_deg=1.0, longitude_deg=2.0, time_ms=time_ms) def test_is_valid_false_when_never_injected(): assert _link().is_valid(1000) is False def test_is_valid_true_when_fresh(): link = _link(timeout_ms=5000) _inject(link, 1000) assert link.is_valid(1000) is True assert link.is_valid(4000) is True def test_is_valid_timeout_boundary(): link = _link(timeout_ms=5000) _inject(link, 1000) assert link.is_valid(6000) is True # 恰好 5000ms,未超龄 assert link.is_valid(6001) is False # 5001ms,超龄 def test_latest_returns_injected_target(): link = _link() _inject(link, 1000) assert link.latest().latitude_deg == pytest.approx(1.0) assert link.latest().time_ms == 1000