using CliFx.Attributes; using CliFx.Infrastructure; using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Driver.S7.Cli; using S7NetCpuType = global::S7.Net.CpuType; namespace ZB.MOM.WW.OtOpcUa.Driver.S7.Cli.Tests; /// /// Covers — the pure, deterministic mapping /// from the base's host/port/CPU/rack/slot/timeout flags onto an /// S7DriverOptions. The CLI is one-shot so the background connectivity probe /// must be disabled. /// [Trait("Category", "Unit")] public sealed class S7CommandBaseBuildOptionsTests { // Test-only S7CommandBase concrete subclass that exposes the protected BuildOptions // helper. The [Command] attribute is required by the CliFx analyzer // (CliFx_CommandMustBeAnnotated) — this command is never registered with the CLI app // but the analyzer rule fires for every ICommand implementor in the compilation. [Command("noop-test", Description = "Test-only probe of S7CommandBase.BuildOptions.")] private sealed class ProbeOnly : S7CommandBase { public override ValueTask ExecuteAsync(IConsole console) => default; public S7DriverOptions Invoke(IReadOnlyList tags) => BuildOptions(tags); } [Fact] public void BuildOptions_disables_probe_for_one_shot_cli_runs() { var sut = new ProbeOnly { Host = "10.0.0.5", Port = 102, CpuType = S7NetCpuType.S71500, Rack = 0, Slot = 0, TimeoutMs = 5000, }; var options = sut.Invoke([]); options.Probe.ShouldNotBeNull(); options.Probe.Enabled.ShouldBeFalse(); } [Fact] public void BuildOptions_maps_TimeoutMs_to_Timeout_TimeSpan() { var sut = new ProbeOnly { Host = "h", TimeoutMs = 7500 }; var options = sut.Invoke([]); options.Timeout.ShouldBe(TimeSpan.FromMilliseconds(7500)); } [Fact] public void BuildOptions_flows_host_port_cpu_rack_slot_through() { var sut = new ProbeOnly { Host = "plc.shop.local", Port = 4102, CpuType = S7NetCpuType.S7300, Rack = 1, Slot = 2, TimeoutMs = 3000, }; var options = sut.Invoke([]); options.Host.ShouldBe("plc.shop.local"); options.Port.ShouldBe(4102); options.CpuType.ShouldBe(S7NetCpuType.S7300); options.Rack.ShouldBe((short)1); options.Slot.ShouldBe((short)2); } [Fact] public void BuildOptions_forwards_tag_list_verbatim() { var sut = new ProbeOnly { Host = "h" }; var tag = new S7TagDefinition("t", "MW0", S7DataType.Int16, Writable: false); var options = sut.Invoke([tag]); options.Tags.Count.ShouldBe(1); options.Tags[0].ShouldBeSameAs(tag); } }