using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Driver.Modbus; namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.Tests; /// /// R2-11 (05/CONV-2): the Modbus probe parses the SAME factory DTO shape the driver factory parses, so /// timeoutMs binds identically instead of being silently dropped (it never bound to the runtime /// ModbusDriverOptions.Timeout TimeSpan). The OpcUaClient probe/factory parse-parity rule. /// public sealed class ModbusDriverProbeParityTests { [Fact] public void Config_timeoutMs_binds_as_the_effective_probe_timeout() { var (target, error) = ModbusDriverProbe.TryParseProbeTarget( "{\"host\":\"10.0.0.5\",\"port\":502,\"unitId\":3,\"timeoutMs\":250}", fallbackTimeout: TimeSpan.FromSeconds(5)); error.ShouldBeNull(); target.ShouldNotBeNull(); target!.Value.Host.ShouldBe("10.0.0.5"); target.Value.Port.ShouldBe(502); target.Value.UnitId.ShouldBe((byte)3); target.Value.Timeout.ShouldBe(TimeSpan.FromMilliseconds(250)); } [Fact] public void Absent_timeoutMs_falls_back_to_the_caller_timeout() { var (target, _) = ModbusDriverProbe.TryParseProbeTarget( "{\"host\":\"10.0.0.5\",\"port\":502}", fallbackTimeout: TimeSpan.FromSeconds(5)); target!.Value.Timeout.ShouldBe(TimeSpan.FromSeconds(5)); target.Value.UnitId.ShouldBe((byte)1); // DTO default } [Fact] public void Missing_host_is_an_error() { var (target, error) = ModbusDriverProbe.TryParseProbeTarget( "{\"port\":0}", fallbackTimeout: TimeSpan.FromSeconds(5)); target.ShouldBeNull(); error.ShouldNotBeNull(); } [Fact] public void Invalid_json_is_an_error() { var (target, error) = ModbusDriverProbe.TryParseProbeTarget( "not valid json {{", fallbackTimeout: TimeSpan.FromSeconds(5)); target.ShouldBeNull(); error.ShouldContain("invalid"); } }