using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.Driver.AbCip;
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip.IntegrationTests;
///
/// Pure-unit tests for the profile → CLI arg composition. Runs without ab_server
/// on PATH so CI without the binary still exercises these contracts + catches any
/// profile-definition drift (e.g. a typo in --plc mapping would silently make the
/// simulator boot with the wrong family).
///
[Trait("Category", "Unit")]
public sealed class AbServerProfileTests
{
[Fact]
public void BuildCliArgs_Emits_Port_And_Plc_And_TagFlags()
{
var profile = new AbServerProfile(
Family: AbCipPlcFamily.ControlLogix,
AbServerPlcArg: "controllogix",
SeedTags: new AbServerSeedTag[]
{
new("A", "DINT"),
new("B", "REAL"),
},
Notes: "test");
profile.BuildCliArgs(44818).ShouldBe("--port 44818 --plc controllogix --tag A:DINT --tag B:REAL");
}
[Fact]
public void BuildCliArgs_NoSeedTags_Emits_Just_Port_And_Plc()
{
var profile = new AbServerProfile(
AbCipPlcFamily.ControlLogix, "controllogix", [], "empty");
profile.BuildCliArgs(5000).ShouldBe("--port 5000 --plc controllogix");
}
[Fact]
public void AbServerSeedTag_ArraySize_FormatsAsThirdSegment()
{
new AbServerSeedTag("TestArray", "DINT", ArraySize: 16)
.ToCliSpec().ShouldBe("TestArray:DINT:16");
}
[Fact]
public void AbServerSeedTag_NoArraySize_TwoSegments()
{
new AbServerSeedTag("TestScalar", "REAL")
.ToCliSpec().ShouldBe("TestScalar:REAL");
}
[Theory]
[InlineData(AbCipPlcFamily.ControlLogix, "controllogix")]
[InlineData(AbCipPlcFamily.CompactLogix, "compactlogix")]
[InlineData(AbCipPlcFamily.Micro800, "controllogix")] // falls back — ab_server lacks dedicated mode
[InlineData(AbCipPlcFamily.GuardLogix, "controllogix")] // falls back — ab_server lacks safety subsystem
public void KnownProfiles_ForFamily_Returns_Expected_AbServerPlcArg(AbCipPlcFamily family, string expected)
{
KnownProfiles.ForFamily(family).AbServerPlcArg.ShouldBe(expected);
}
[Fact]
public void KnownProfiles_All_Covers_Every_Family()
{
var covered = KnownProfiles.All.Select(p => p.Family).ToHashSet();
foreach (var family in Enum.GetValues())
covered.ShouldContain(family, $"Family {family} is missing a KnownProfiles entry.");
}
[Fact]
public void KnownProfiles_ControlLogix_Includes_AllAtomicTypes()
{
var tags = KnownProfiles.ControlLogix.SeedTags.Select(t => t.AbServerType).ToHashSet();
tags.ShouldContain("DINT");
tags.ShouldContain("REAL");
tags.ShouldContain("BOOL");
tags.ShouldContain("SINT");
tags.ShouldContain("STRING");
}
[Fact]
public void KnownProfiles_GuardLogix_SeedsSafetySuffixedTag()
{
KnownProfiles.GuardLogix.SeedTags
.ShouldContain(t => t.Name.EndsWith("_S"), "GuardLogix profile must seed at least one _S-suffixed tag for safety-classification coverage.");
}
}