"""Tests for motion-pair cache IO.""" from __future__ import annotations from pathlib import Path import numpy as np from imu_lidar.contracts import MotionPair from imu_lidar.motion_pairs_io import ( build_motion_pairs_payload, load_motion_pairs, pair_from_dict, pair_to_dict, pairs_for_session, save_motion_pairs, ) def test_pair_roundtrip(tmp_path: Path) -> None: pair = MotionPair( session_id="s0", i=1, j=4, t_i_s=1.0, t_j_s=2.5, R_A=np.eye(3), R_B=np.eye(3), t_A_m=np.array([0.1, 0.0, 0.0]), t_B_m=np.array([0.1, 0.0, 0.0]), fitness=0.8, metadata={ "weight": 12.0, "cov": (np.eye(3) * 1e-4).tolist(), "J_bg": (-np.eye(3)).tolist(), "cov9": [[0.0] * 9] * 9, "backend": "test", "gyro_bias0_rad_s": [0.01, -0.02, 0.03], "accel_bias0_m_s2": [0.1, 0.2, -0.1], "time_offset_s": 0.004, "keyframe_span": 3, "is_consecutive": False, }, ) encoded = pair_to_dict(pair) assert "cov9" not in encoded["metadata"] assert "cov" in encoded["metadata"] assert "J_bg" in encoded["metadata"] assert encoded["metadata"]["weight"] == 12.0 restored = pair_from_dict(encoded) assert restored.i == 1 and restored.j == 4 np.testing.assert_allclose(restored.t_A_m, [0.1, 0.0, 0.0]) np.testing.assert_allclose(restored.metadata["gyro_bias0_rad_s"], [0.01, -0.02, 0.03]) assert restored.metadata["keyframe_span"] == 3 payload = build_motion_pairs_payload( prepared_sessions=[ { "session_id": "s0", "time_offset_s": 0.0, "gyro_bias_rad_s": np.zeros(3), "pairs": (pair,), } ] ) path = save_motion_pairs(tmp_path / "motion_pairs.json", payload) loaded = load_motion_pairs(path) assert loaded["schema_version"] == 2 pairs = pairs_for_session(loaded, "s0") assert len(pairs) == 1 assert pairs[0].session_id == "s0" payload["schema_version"] = 1 legacy_path = save_motion_pairs( tmp_path / "motion_pairs_v1.json", payload ) legacy = load_motion_pairs(legacy_path) assert legacy["schema_version"] == 1