120 lines
5.1 KiB
C#
120 lines
5.1 KiB
C#
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
using ZB.MOM.WW.OtOpcUa.Runtime.Drivers;
|
|
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Runtime.Tests.Drivers;
|
|
|
|
[Trait("Category", "Unit")]
|
|
public sealed class DiscoveredNodeMapperTests
|
|
{
|
|
private static DiscoveredNode Node(string[] path, string name, string fullRef,
|
|
DriverDataType dt = DriverDataType.Float64, bool writable = false)
|
|
=> new(path, name, name, fullRef, dt, false, null, writable, false);
|
|
|
|
[Fact]
|
|
public void Maps_under_equipment_collapsing_single_device_folder()
|
|
{
|
|
var nodes = new[]
|
|
{
|
|
Node(["FOCAS", "10.0.0.5:8193", "Identity"], "SeriesNumber", "10.0.0.5:8193/Identity/SeriesNumber", DriverDataType.String),
|
|
Node(["FOCAS", "10.0.0.5:8193", "Axes", "X"], "AbsolutePosition", "10.0.0.5:8193/Axes/X/AbsolutePosition"),
|
|
};
|
|
|
|
var result = DiscoveredNodeMapper.Map("EQ-1", nodes, authoredRefs: new HashSet<string>());
|
|
|
|
result.Variables.Select(v => v.NodeId).ShouldBe(new[]
|
|
{
|
|
"EQ-1/FOCAS/Identity/SeriesNumber",
|
|
"EQ-1/FOCAS/Axes/X/AbsolutePosition",
|
|
}, ignoreOrder: true);
|
|
result.Folders.Select(f => f.NodeId).ShouldContain("EQ-1/FOCAS/Axes/X");
|
|
result.Folders.First(f => f.NodeId == "EQ-1/FOCAS/Axes/X").ParentNodeId.ShouldBe("EQ-1/FOCAS/Axes");
|
|
result.RoutingByRef["10.0.0.5:8193/Identity/SeriesNumber"].ShouldBe("EQ-1/FOCAS/Identity/SeriesNumber");
|
|
result.Variables.First(v => v.NodeId.EndsWith("SeriesNumber")).Writable.ShouldBeFalse();
|
|
}
|
|
|
|
[Fact]
|
|
public void Dedups_authored_refs()
|
|
{
|
|
var nodes = new[]
|
|
{
|
|
Node(["FOCAS", "10.0.0.5:8193"], "parts-count", "parts-count"),
|
|
Node(["FOCAS", "10.0.0.5:8193", "Identity"], "SeriesNumber", "10.0.0.5:8193/Identity/SeriesNumber", DriverDataType.String),
|
|
};
|
|
var result = DiscoveredNodeMapper.Map("EQ-1", nodes, authoredRefs: new HashSet<string> { "parts-count" });
|
|
result.Variables.ShouldHaveSingleItem();
|
|
result.Variables[0].NodeId.ShouldBe("EQ-1/FOCAS/Identity/SeriesNumber");
|
|
}
|
|
|
|
[Fact]
|
|
public void Does_not_collapse_when_two_devices_present()
|
|
{
|
|
var nodes = new[]
|
|
{
|
|
Node(["FOCAS", "10.0.0.5:8193", "Identity"], "SeriesNumber", "a", DriverDataType.String),
|
|
Node(["FOCAS", "10.0.0.6:8193", "Identity"], "SeriesNumber", "b", DriverDataType.String),
|
|
};
|
|
var result = DiscoveredNodeMapper.Map("EQ-1", nodes, authoredRefs: new HashSet<string>());
|
|
result.Variables.Select(v => v.NodeId).ShouldBe(new[]
|
|
{
|
|
"EQ-1/FOCAS/10.0.0.5:8193/Identity/SeriesNumber",
|
|
"EQ-1/FOCAS/10.0.0.6:8193/Identity/SeriesNumber",
|
|
}, ignoreOrder: true);
|
|
}
|
|
|
|
[Fact]
|
|
public void Empty_input_yields_empty_plan()
|
|
{
|
|
var result = DiscoveredNodeMapper.Map("EQ-1", Array.Empty<DiscoveredNode>(), authoredRefs: new HashSet<string>());
|
|
result.Folders.ShouldBeEmpty();
|
|
result.Variables.ShouldBeEmpty();
|
|
result.RoutingByRef.ShouldBeEmpty();
|
|
}
|
|
|
|
[Fact]
|
|
public void Array_metadata_passes_through_unchanged()
|
|
{
|
|
var node = new DiscoveredNode(
|
|
FolderPathSegments: ["FOCAS", "10.0.0.5:8193", "Axes"],
|
|
BrowseName: "Positions",
|
|
DisplayName: "Positions",
|
|
FullReference: "10.0.0.5:8193/Axes/Positions",
|
|
DataType: DriverDataType.Float64,
|
|
IsArray: true,
|
|
ArrayDim: 8u,
|
|
Writable: false,
|
|
IsHistorized: false);
|
|
|
|
var result = DiscoveredNodeMapper.Map("EQ-1", new[] { node }, authoredRefs: new HashSet<string>());
|
|
|
|
result.Variables.ShouldHaveSingleItem();
|
|
result.Variables[0].IsArray.ShouldBeTrue();
|
|
result.Variables[0].ArrayLength.ShouldBe(8u);
|
|
}
|
|
|
|
[Theory]
|
|
// Mirror OtOpcUaNodeManager.ResolveBuiltInDataType's accepted string set: Float32 -> "Float",
|
|
// Float64 -> "Double", Reference (Galaxy attr ref encoded as a string) -> "String". The pass-through
|
|
// members must keep their enum name so the node manager resolves them to the matching built-in type.
|
|
[InlineData(DriverDataType.Float64, "Double")]
|
|
[InlineData(DriverDataType.Float32, "Float")]
|
|
[InlineData(DriverDataType.Reference, "String")]
|
|
[InlineData(DriverDataType.Boolean, "Boolean")]
|
|
[InlineData(DriverDataType.Int16, "Int16")]
|
|
[InlineData(DriverDataType.Int32, "Int32")]
|
|
[InlineData(DriverDataType.Int64, "Int64")]
|
|
[InlineData(DriverDataType.UInt16, "UInt16")]
|
|
[InlineData(DriverDataType.UInt32, "UInt32")]
|
|
[InlineData(DriverDataType.UInt64, "UInt64")]
|
|
[InlineData(DriverDataType.String, "String")]
|
|
[InlineData(DriverDataType.DateTime, "DateTime")]
|
|
public void DataType_maps_to_node_manager_builtin_string(DriverDataType dt, string expected)
|
|
{
|
|
var nodes = new[] { Node(["FOCAS", "10.0.0.5:8193", "Identity"], "Value", "10.0.0.5:8193/Identity/Value", dt) };
|
|
var result = DiscoveredNodeMapper.Map("EQ-1", nodes, authoredRefs: new HashSet<string>());
|
|
result.Variables.ShouldHaveSingleItem();
|
|
result.Variables[0].DataType.ShouldBe(expected);
|
|
}
|
|
}
|