using System; using IvfTl.ControlHost.Debug; using IvfTl.ControlHost.Tests.Fakes; using Xunit; namespace IvfTl.ControlHost.Tests { /// /// D2-02 Task3.2a:CalibrationManager 的 sid 校验路径(不触真实硬件标定)。 /// 真实标定要硬件,这里只断言会话校验/字典管理的纯逻辑分支: /// · 不存在的 sid → StartCalibrate / GetProgress / Recalibrate 返回 SESSION_EXPIRED; /// · Stop 未知 sid 幂等返回 Okay; /// · houseBinOf 委托在 SESSION_EXPIRED 路径上绝不被调用(closure 未进入)。 /// public class CalibrationManagerTests { private DateTime _now = new DateTime(2026, 6, 25, 0, 0, 0); private (CalibrationManager calib, DebugSessionManager debug, bool[] houseBinTouched) New() { var serial = new FakeSerial(); var gate = new FakeGate(7, serial) { CanAcquire = true }; var debug = new DebugSessionManager(sn => gate, () => _now, ttlMs: 10000, log: _ => { }); var touched = new bool[1]; // houseBinOf:SESSION_EXPIRED 路径下绝不应被调用;被调用则置标志,便于断言。 var calib = new CalibrationManager(debug, sn => { touched[0] = true; return null; }, log: _ => { }); return (calib, debug, touched); } [Fact] public void StartCalibrate_Unknown_Sid_Returns_SESSION_EXPIRED_Without_Touching_HouseBin() { var (calib, _, touched) = New(); var r = calib.StartCalibrate("not-a-session", null); Assert.False(r.Ok); Assert.Equal("SESSION_EXPIRED", r.Code); Assert.False(touched[0]); // 会话校验先于取 HouseBin,委托不被触发 } [Fact] public void GetProgress_Unknown_Sid_Returns_SESSION_EXPIRED() { var (calib, _, _) = New(); var r = calib.GetProgress("nope"); Assert.False(r.Ok); Assert.Equal("SESSION_EXPIRED", r.Code); } [Fact] public void Recalibrate_Unknown_Sid_Returns_SESSION_EXPIRED() { var (calib, _, _) = New(); var r = calib.Recalibrate("nope", 3); Assert.False(r.Ok); Assert.Equal("SESSION_EXPIRED", r.Code); } [Fact] public void Stop_Unknown_Sid_Is_Idempotent_Ok() { var (calib, _, _) = New(); Assert.True(calib.Stop("nope").Ok); Assert.True(calib.Stop(null).Ok); } } }