Просмотр исходного кода

feat(d2-02-t3): control 补缓冲瓶 op(BufferState/Aeration/ReadLight/WriteLight/WriteOpenIntakeTimeBuffer)+5单测

huangjie 3 дней назад
Родитель
Сommit
bf4b6e7018

+ 90 - 0
ivf_tl_operate_2.0/control/IvfTl.ControlHost.Tests/DebugBufferOpTests.cs

@@ -0,0 +1,90 @@
+using System;
+using IvfTl.ControlHost.Debug;
+using IvfTl.ControlHost.Tests.Fakes;
+using Newtonsoft.Json.Linq;
+using Xunit;
+
+namespace IvfTl.ControlHost.Tests
+{
+    /// <summary>缓冲瓶(舱11)专属 op 路由测试:验证 Execute 把 5 个 op 分发到正确底层方法。</summary>
+    public class DebugBufferOpTests
+    {
+        private static readonly DateTime Now = new DateTime(2026, 6, 24, 0, 0, 0, DateTimeKind.Utc);
+
+        // 返回 (manager, sid, fakeSerial) 三件套,照 DebugStreamSessionTests 的装配方式
+        private (DebugSessionManager mgr, string sid, FakeSerial ser) NewSession()
+        {
+            var ser = new FakeSerial();
+            var gate = new FakeGate(11, ser);
+            var mgr = new DebugSessionManager(_ => gate, () => Now, ttlMs: 10000, log: null);
+            string sid = (string)mgr.Acquire(11).Result;
+            return (mgr, sid, ser);
+        }
+
+        [Fact]
+        public void BufferState_RoutesTo_BufferBottleStateWait_AndReturnsTuple()
+        {
+            var (mgr, sid, ser) = NewSession();
+            ser.BufferStateReturn = (2.5m, 36.1m, 37.2m);
+
+            var r = mgr.Execute(sid, "BufferState", null);
+
+            Assert.True(r.Ok);
+            Assert.Contains("BufferState", ser.Calls);
+            var jo = JObject.FromObject(r.Result);
+            Assert.Equal(2.5m, jo["pressure"].Value<decimal>());
+            Assert.Equal(36.1m, jo["t1"].Value<decimal>());
+            Assert.Equal(37.2m, jo["t2"].Value<decimal>());
+        }
+
+        [Fact]
+        public void BufferAeration_RoutesTo_BufferBottleAerationWait()
+        {
+            var (mgr, sid, ser) = NewSession();
+
+            var r = mgr.Execute(sid, "BufferAeration", null);
+
+            Assert.True(r.Ok);
+            Assert.Equal(true, r.Result);
+            Assert.Contains("BufferAeration", ser.Calls);
+        }
+
+        [Fact]
+        public void ReadLight_RoutesTo_ReadLightBrightnessWait_AndReturnsInt()
+        {
+            var (mgr, sid, ser) = NewSession();
+
+            var r = mgr.Execute(sid, "ReadLight", null);
+
+            Assert.True(r.Ok);
+            Assert.Equal(500, r.Result);   // FakeSerial.ReadLightBrightnessWait 固定返回 500
+            Assert.Contains("ReadLight", ser.Calls);
+        }
+
+        [Fact]
+        public void WriteLight_RoutesTo_WriteLightBrightnessWait_WithValue()
+        {
+            var (mgr, sid, ser) = NewSession();
+            var args = new JObject { ["value"] = 320 };
+
+            var r = mgr.Execute(sid, "WriteLight", args);
+
+            Assert.True(r.Ok);
+            Assert.Contains("WriteLight(320)", ser.Calls);
+            Assert.Equal(320, ser.LastWriteLight);
+        }
+
+        [Fact]
+        public void WriteOpenIntakeTimeBuffer_RoutesTo_WriteOpenIntakeTimeWait_WithIsBufferTrue()
+        {
+            var (mgr, sid, ser) = NewSession();
+            var args = new JObject { ["value"] = 150 };
+
+            var r = mgr.Execute(sid, "WriteOpenIntakeTimeBuffer", args);
+
+            Assert.True(r.Ok);
+            Assert.Equal(150, ser.LastWriteIntake);
+            Assert.True(ser.LastWriteIntakeIsBuffer);
+        }
+    }
+}

+ 7 - 4
ivf_tl_operate_2.0/control/IvfTl.ControlHost.Tests/Fakes/FakeHardware.cs

@@ -23,10 +23,12 @@ namespace IvfTl.ControlHost.Tests.Fakes
         public int ReadScanStepWait() => -1;
         public bool WriteWellHorizontalPosWait(int well, int p) { Calls.Add($"WriteWellHor({well},{p})"); return true; }
         public bool WriteScanStepWait(int p) { Calls.Add($"WriteScanStep({p})"); return true; }
-        public bool WriteOpenIntakeTimeWait(int v, bool b = false) { Calls.Add($"WriteIntake({v})"); return true; }
+        public int LastWriteIntake; public bool LastWriteIntakeIsBuffer;
+        public bool WriteOpenIntakeTimeWait(int v, bool b = false) { Calls.Add($"WriteIntake({v})"); LastWriteIntake = v; LastWriteIntakeIsBuffer = b; return true; }
         public bool WriteOpenVentTimeWait(int v) { Calls.Add($"WriteVent({v})"); return true; }
         public int ReadOpenVentTimeWait() { Calls.Add("ReadVent"); return 200; }
-        public bool WriteLightBrightnessWait(int v) { Calls.Add($"WriteLight({v})"); return true; }
+        public int LastWriteLight;
+        public bool WriteLightBrightnessWait(int v) { Calls.Add($"WriteLight({v})"); LastWriteLight = v; return true; }
         public int VerPos;
         public int HorPos;
         public bool VerticalMoveToWait(int p, int d = -1) { Calls.Add($"VMoveTo({p})"); VerPos = p; return true; }
@@ -43,7 +45,8 @@ namespace IvfTl.ControlHost.Tests.Fakes
         public decimal ShangTemperatureWait() => 37.0m;
         public decimal BoLiTemperatureWait() => 37.0m;
         public decimal PressureWait() { Calls.Add("Pressure"); return 1.0m; }
-        public (decimal, decimal, decimal) BufferBottleStateWait() => (1m, 37m, 37m);
+        public (decimal, decimal, decimal) BufferStateReturn = (1m, 37m, 37m);
+        public (decimal, decimal, decimal) BufferBottleStateWait() { Calls.Add("BufferState"); return BufferStateReturn; }
         public DoorState DoorStatusWait() { Calls.Add("Door"); return DoorState.关闭; }
         public bool OpenLedWait() { Calls.Add("OpenLed"); return true; }
         public bool CloseLedWait() { Calls.Add("CloseLed"); return true; }
@@ -53,7 +56,7 @@ namespace IvfTl.ControlHost.Tests.Fakes
         public bool CloseExhaustValveWait() { Calls.Add("CloseExhaust"); return true; }
         public bool HouseAerationWait() { Calls.Add("Aeration"); return true; }
         public bool HouseVentWait() { Calls.Add("Vent"); return true; }
-        public bool BufferBottleAerationWait() => true;
+        public bool BufferBottleAerationWait() { Calls.Add("BufferAeration"); return true; }
         public bool AutoAirSwapWait(bool on) => true;
         public object RawComBin => null;
         public void Dispose() => Calls.Add("Dispose");

+ 17 - 0
ivf_tl_operate_2.0/control/ivf_tl_ControlHost/Debug/DebugSessionManager.cs

@@ -93,6 +93,23 @@ namespace IvfTl.ControlHost.Debug
                     case "CloseExhaust": return DebugCommandResult.Okay(ser.CloseExhaustValveWait());
                     case "HouseAeration": return DebugCommandResult.Okay(ser.HouseAerationWait());
                     case "HouseVent": return DebugCommandResult.Okay(ser.HouseVentWait());
+                    case "BufferState":
+                    {
+                        var (pressure, t1, t2) = ser.BufferBottleStateWait();
+                        return DebugCommandResult.Okay(new { pressure, t1, t2 });
+                    }
+                    case "BufferAeration": return DebugCommandResult.Okay(ser.BufferBottleAerationWait());
+                    case "ReadLight": return DebugCommandResult.Okay(ser.ReadLightBrightnessWait());
+                    case "WriteLight":
+                    {
+                        int v = args?["value"] != null ? args["value"].Value<int>() : 0;
+                        return DebugCommandResult.Okay(ser.WriteLightBrightnessWait(v));
+                    }
+                    case "WriteOpenIntakeTimeBuffer":
+                    {
+                        int v = args?["value"] != null ? args["value"].Value<int>() : 0;
+                        return DebugCommandResult.Okay(ser.WriteOpenIntakeTimeWait(v, isBuffer: true));
+                    }
                     default:
                         return ExecuteMotorOrEeprom(s, ser, op, args);
                 }