using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using ivf_tl_Operate.Debug;
using Newtonsoft.Json.Linq;
using Xunit;
namespace IvfTl.ControlHost.Tests
{
///
/// operate 端 CalibrationClient 纯逻辑单测:用 fake HttpMessageHandler 注入 control 端
/// /debug/calibrate/* 的响应,验证四个端点的路径/请求体/解析。
/// 进度响应是 control 端 JsonConvert.SerializeObject(DebugCommandResult)——result 内嵌
/// CalibProgress(PascalCase 字段,WellCalibState 枚举默认序列化为数字)。
///
public class CalibrationClientTests
{
private sealed class FakeHandler : HttpMessageHandler
{
public Func Responder;
public string LastPath;
public string LastBody;
protected override async Task SendAsync(HttpRequestMessage req, CancellationToken ct)
{
LastPath = req.RequestUri.AbsolutePath;
LastBody = req.Content != null ? await req.Content.ReadAsStringAsync() : "";
var (code, body) = Responder(req, LastBody);
return new HttpResponseMessage(code) { Content = new StringContent(body) };
}
}
private const string Sid = "sid123";
[Fact]
public async Task StartAsync_PostsToStart_WithSessionIdAndWells_ParsesOk()
{
var h = new FakeHandler { Responder = (_, __) => (HttpStatusCode.OK, "{\"ok\":true}") };
var c = new CalibrationClient("http://127.0.0.1:9/", Sid, new HttpClient(h));
var r = await c.StartAsync(new[] { 1, 2, 3 });
Assert.True(r.Ok);
Assert.Equal("/debug/calibrate/start", h.LastPath);
var jo = JObject.Parse(h.LastBody);
Assert.Equal(Sid, jo["sessionId"]?.ToString());
Assert.Equal(new[] { 1, 2, 3 }, ((JArray)jo["wells"]).ToObject());
}
[Fact]
public async Task PollProgressAsync_ParsesCalibProgress_TotalCompletedIsRunning_AndWells()
{
// control 端真实形态:DebugCommandResult{ok, result=CalibProgress}(PascalCase,枚举=数字)。
string body =
"{\"ok\":true,\"result\":{" +
"\"Total\":16,\"Completed\":2,\"CurrentWell\":3,\"IsRunning\":true,\"Wells\":[" +
"{\"WellSn\":1,\"State\":2,\"FocusZ\":90000,\"Exposure\":120,\"PeakRatio\":1.8,\"CenterOffsetPct\":0.5,\"CircleFound\":true,\"Note\":\"\"}," +
"{\"WellSn\":2,\"State\":3,\"FocusZ\":0,\"Exposure\":0,\"PeakRatio\":1.0,\"CenterOffsetPct\":0.0,\"CircleFound\":false,\"Note\":\"伪峰\"}" +
"]}}";
var h = new FakeHandler { Responder = (_, __) => (HttpStatusCode.OK, body) };
var c = new CalibrationClient("http://127.0.0.1:9/", Sid, new HttpClient(h));
var p = await c.PollProgressAsync();
Assert.Equal("/debug/calibrate/progress", h.LastPath);
Assert.Equal(Sid, JObject.Parse(h.LastBody)["sessionId"]?.ToString());
Assert.NotNull(p);
Assert.Equal(16, p.Total);
Assert.Equal(2, p.Completed);
Assert.Equal(3, p.CurrentWell);
Assert.True(p.IsRunning);
Assert.Equal(2, p.Wells.Count);
Assert.Equal(1, p.Wells[0].WellSn);
Assert.Equal(2, p.Wells[0].State); // Qualified=2
Assert.Equal(90000, p.Wells[0].FocusZ);
Assert.True(p.Wells[0].CircleFound);
Assert.Equal(1.8, p.Wells[0].PeakRatio, 3);
Assert.Equal(3, p.Wells[1].State); // FakePeak=3
Assert.Equal("伪峰", p.Wells[1].Note);
}
[Fact]
public async Task RecalibrateAsync_PostsToRecalibrate_WithWellSn()
{
var h = new FakeHandler { Responder = (_, __) => (HttpStatusCode.OK, "{\"ok\":true,\"result\":true}") };
var c = new CalibrationClient("http://127.0.0.1:9/", Sid, new HttpClient(h));
var r = await c.RecalibrateAsync(7);
Assert.True(r.Ok);
Assert.Equal("/debug/calibrate/recalibrate", h.LastPath);
var jo = JObject.Parse(h.LastBody);
Assert.Equal(Sid, jo["sessionId"]?.ToString());
Assert.Equal(7, (int)jo["wellSn"]);
}
[Fact]
public async Task StopAsync_PostsToStop_WithSessionId()
{
var h = new FakeHandler { Responder = (_, __) => (HttpStatusCode.OK, "{\"ok\":true}") };
var c = new CalibrationClient("http://127.0.0.1:9/", Sid, new HttpClient(h));
var r = await c.StopAsync();
Assert.True(r.Ok);
Assert.Equal("/debug/calibrate/stop", h.LastPath);
Assert.Equal(Sid, JObject.Parse(h.LastBody)["sessionId"]?.ToString());
}
[Fact]
public async Task SessionExpired_CodeIsReadable()
{
var h = new FakeHandler { Responder = (_, __) => (HttpStatusCode.Gone, "{\"ok\":false,\"code\":\"SESSION_EXPIRED\",\"error\":\"会话不存在或已过期\"}") };
var c = new CalibrationClient("http://127.0.0.1:9/", Sid, new HttpClient(h));
var r = await c.StartAsync();
Assert.False(r.Ok);
Assert.Equal("SESSION_EXPIRED", r.Code);
}
}
}