using Opc.Ua; using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests; [Trait("Category", "Unit")] public sealed class OpcUaClientAttributeMappingTests { [Theory] [InlineData((uint)DataTypes.Boolean, DriverDataType.Boolean)] [InlineData((uint)DataTypes.SByte, DriverDataType.Int16)] [InlineData((uint)DataTypes.Byte, DriverDataType.UInt16)] [InlineData((uint)DataTypes.Int16, DriverDataType.Int16)] [InlineData((uint)DataTypes.UInt16, DriverDataType.UInt16)] [InlineData((uint)DataTypes.Int32, DriverDataType.Int32)] [InlineData((uint)DataTypes.UInt32, DriverDataType.UInt32)] [InlineData((uint)DataTypes.Int64, DriverDataType.Int64)] [InlineData((uint)DataTypes.UInt64, DriverDataType.UInt64)] [InlineData((uint)DataTypes.Float, DriverDataType.Float32)] [InlineData((uint)DataTypes.Double, DriverDataType.Float64)] [InlineData((uint)DataTypes.String, DriverDataType.String)] [InlineData((uint)DataTypes.DateTime, DriverDataType.DateTime)] public void MapUpstreamDataType_recognizes_standard_builtin_types(uint typeId, DriverDataType expected) { var nodeId = new NodeId(typeId); OpcUaClientDriver.MapUpstreamDataType(nodeId).ShouldBe(expected); } [Fact] public void MapUpstreamDataType_maps_SByte_to_Int16_since_DriverDataType_lacks_8bit_signed() { // SByte (signed 8-bit) has no narrower signed type in DriverDataType; widen to Int16. OpcUaClientDriver.MapUpstreamDataType(new NodeId((uint)DataTypes.SByte)).ShouldBe(DriverDataType.Int16); } [Fact] public void MapUpstreamDataType_maps_Byte_to_UInt16_not_Int16() { // Driver.OpcUaClient-010: Byte is unsigned 0-255 and must map to the unsigned family // (UInt16), NOT Int16. The old mapping misrepresented type metadata for downstream // clients and range/validation logic keyed off DriverDataType. OpcUaClientDriver.MapUpstreamDataType(new NodeId((uint)DataTypes.Byte)).ShouldBe(DriverDataType.UInt16); } [Fact] public void MapUpstreamDataType_falls_back_to_String_for_unknown_custom_types() { // Custom vendor extension object — NodeId in namespace 2 that isn't a standard type. OpcUaClientDriver.MapUpstreamDataType(new NodeId("CustomStruct", 2)).ShouldBe(DriverDataType.String); } [Fact] public void MapUpstreamDataType_handles_UtcTime_as_DateTime() { OpcUaClientDriver.MapUpstreamDataType(new NodeId((uint)DataTypes.UtcTime)).ShouldBe(DriverDataType.DateTime); } [Theory] [InlineData((byte)0, SecurityClassification.ViewOnly)] // no access flags set [InlineData((byte)1, SecurityClassification.ViewOnly)] // CurrentRead only [InlineData((byte)2, SecurityClassification.Operate)] // CurrentWrite only [InlineData((byte)3, SecurityClassification.Operate)] // CurrentRead + CurrentWrite [InlineData((byte)0x0F, SecurityClassification.Operate)] // read+write+historyRead+historyWrite [InlineData((byte)0x04, SecurityClassification.ViewOnly)] // HistoryRead only — no Write bit public void MapAccessLevelToSecurityClass_respects_CurrentWrite_bit(byte accessLevel, SecurityClassification expected) { OpcUaClientDriver.MapAccessLevelToSecurityClass(accessLevel).ShouldBe(expected); } }