review(Driver.AbCip): thread ElementCount/IsArray through factory tag DTOs
Cross-module fix from the review sweep. -018 (Medium): AbCipTagDto/AbCipMemberDto dropped elementCount/isArray, so driver-config-authored array tags read as a single scalar. Added the two optional JSON fields (additive; missing -> scalar as before) threaded into the tag def + TDD.
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Driver.AbCip;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Driver.AbCip.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Regression coverage for Driver.AbCip-018 — the driver-config factory path
|
||||
/// (<see cref="AbCipDriverFactoryExtensions.ParseOptions"/>) dropped the array shape of a
|
||||
/// pre-declared tag. A <c>tags[]</c> entry with <c>"isArray": true, "elementCount": 4</c>
|
||||
/// deserialised into a scalar <see cref="AbCipTagDefinition"/> (because <c>AbCipTagDto</c> /
|
||||
/// <c>AbCipMemberDto</c> had no <c>ElementCount</c> / <c>IsArray</c> fields), so the tag read
|
||||
/// as a single scalar despite the explicit array declaration. These tests assert the array
|
||||
/// shape now survives factory deserialization for both top-level tags and UDT members, and
|
||||
/// that omitting the fields keeps the legacy scalar default (additive change — no break).
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class AbCipFactoryArrayTagTests
|
||||
{
|
||||
/// <summary>A driver-config tag declaring isArray/elementCount produces an array definition.</summary>
|
||||
[Fact]
|
||||
public void ParseOptions_threads_isArray_and_elementCount_into_tag_definition()
|
||||
{
|
||||
const string json = """
|
||||
{
|
||||
"Tags": [ {
|
||||
"Name": "Setpoints",
|
||||
"DeviceHostAddress": "ab://10.0.0.5/1,0",
|
||||
"TagPath": "Setpoints",
|
||||
"DataType": "Real",
|
||||
"isArray": true,
|
||||
"elementCount": 4
|
||||
} ]
|
||||
}
|
||||
""";
|
||||
|
||||
var opts = AbCipDriverFactoryExtensions.ParseOptions("drv-1", json);
|
||||
|
||||
var tag = opts.Tags.Single();
|
||||
tag.IsArray.ShouldBeTrue();
|
||||
tag.ElementCount.ShouldBe(4);
|
||||
}
|
||||
|
||||
/// <summary>A driver-config UDT member declaring isArray/elementCount produces an array member.</summary>
|
||||
[Fact]
|
||||
public void ParseOptions_threads_isArray_and_elementCount_into_structure_member()
|
||||
{
|
||||
const string json = """
|
||||
{
|
||||
"Tags": [ {
|
||||
"Name": "Motor",
|
||||
"DeviceHostAddress": "ab://10.0.0.5/1,0",
|
||||
"TagPath": "Motor",
|
||||
"DataType": "Structure",
|
||||
"Members": [ {
|
||||
"Name": "Setpoints",
|
||||
"DataType": "Real",
|
||||
"isArray": true,
|
||||
"elementCount": 4
|
||||
} ]
|
||||
} ]
|
||||
}
|
||||
""";
|
||||
|
||||
var opts = AbCipDriverFactoryExtensions.ParseOptions("drv-1", json);
|
||||
|
||||
var member = opts.Tags.Single().Members!.Single();
|
||||
member.IsArray.ShouldBeTrue();
|
||||
member.ElementCount.ShouldBe(4);
|
||||
}
|
||||
|
||||
/// <summary>A driver-config tag without array fields stays scalar (additive change — no break).</summary>
|
||||
[Fact]
|
||||
public void ParseOptions_defaults_to_scalar_when_array_fields_absent()
|
||||
{
|
||||
const string json = """
|
||||
{
|
||||
"Tags": [ {
|
||||
"Name": "Speed",
|
||||
"DeviceHostAddress": "ab://10.0.0.5/1,0",
|
||||
"TagPath": "Speed",
|
||||
"DataType": "DInt"
|
||||
} ]
|
||||
}
|
||||
""";
|
||||
|
||||
var opts = AbCipDriverFactoryExtensions.ParseOptions("drv-1", json);
|
||||
|
||||
var tag = opts.Tags.Single();
|
||||
tag.IsArray.ShouldBeFalse();
|
||||
tag.ElementCount.ShouldBe(1);
|
||||
}
|
||||
|
||||
/// <summary>A non-positive elementCount falls back to the scalar count of 1 (positive-value guard).</summary>
|
||||
[Fact]
|
||||
public void ParseOptions_guards_against_non_positive_elementCount()
|
||||
{
|
||||
const string json = """
|
||||
{
|
||||
"Tags": [ {
|
||||
"Name": "Speed",
|
||||
"DeviceHostAddress": "ab://10.0.0.5/1,0",
|
||||
"TagPath": "Speed",
|
||||
"DataType": "DInt",
|
||||
"isArray": true,
|
||||
"elementCount": 0
|
||||
} ]
|
||||
}
|
||||
""";
|
||||
|
||||
var opts = AbCipDriverFactoryExtensions.ParseOptions("drv-1", json);
|
||||
|
||||
var tag = opts.Tags.Single();
|
||||
// elementCount <= 0 is degenerate — count clamps to 1; the explicit IsArray flag still
|
||||
// carries (a 1-element array is valid), mirroring the equipment-tag parser's contract.
|
||||
tag.ElementCount.ShouldBe(1);
|
||||
tag.IsArray.ShouldBeTrue();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user