using System; using Shouldly; using Xunit; using ZB.MOM.WW.LmxOpcUa.Host.Domain; using ZB.MOM.WW.LmxOpcUa.Host.OpcUa; namespace ZB.MOM.WW.LmxOpcUa.Tests.OpcUa { /// /// Verifies how bridge VTQ values are translated to and from OPC UA data values for the published namespace. /// public class DataValueConverterTests { /// /// Confirms that boolean runtime values are preserved when converted to OPC UA data values. /// [Fact] public void FromVtq_Boolean() { var vtq = Vtq.Good(true); var dv = DataValueConverter.FromVtq(vtq); dv.Value.ShouldBe(true); Opc.Ua.StatusCode.IsGood(dv.StatusCode).ShouldBe(true); } /// /// Confirms that integer runtime values are preserved when converted to OPC UA data values. /// [Fact] public void FromVtq_Int32() { var vtq = Vtq.Good(42); var dv = DataValueConverter.FromVtq(vtq); dv.Value.ShouldBe(42); } /// /// Confirms that float runtime values are preserved when converted to OPC UA data values. /// [Fact] public void FromVtq_Float() { var vtq = Vtq.Good(3.14f); var dv = DataValueConverter.FromVtq(vtq); dv.Value.ShouldBe(3.14f); } /// /// Confirms that double runtime values are preserved when converted to OPC UA data values. /// [Fact] public void FromVtq_Double() { var vtq = Vtq.Good(3.14159); var dv = DataValueConverter.FromVtq(vtq); dv.Value.ShouldBe(3.14159); } /// /// Confirms that string runtime values are preserved when converted to OPC UA data values. /// [Fact] public void FromVtq_String() { var vtq = Vtq.Good("hello"); var dv = DataValueConverter.FromVtq(vtq); dv.Value.ShouldBe("hello"); } /// /// Confirms that UTC timestamps remain UTC when a VTQ is converted for OPC UA clients. /// [Fact] public void FromVtq_DateTime_IsUtc() { var utcTime = new DateTime(2024, 6, 15, 10, 30, 0, DateTimeKind.Utc); var vtq = new Vtq(utcTime, utcTime, Quality.Good); var dv = DataValueConverter.FromVtq(vtq); ((DateTime)dv.Value).Kind.ShouldBe(DateTimeKind.Utc); } /// /// Confirms that elapsed-time values are exposed to OPC UA clients in seconds. /// [Fact] public void FromVtq_TimeSpan_ConvertedToSeconds() { var vtq = Vtq.Good(TimeSpan.FromMinutes(2.5)); var dv = DataValueConverter.FromVtq(vtq); dv.Value.ShouldBe(150.0); } /// /// Confirms that string arrays remain arrays when exposed through OPC UA. /// [Fact] public void FromVtq_StringArray() { var arr = new[] { "a", "b", "c" }; var vtq = Vtq.Good(arr); var dv = DataValueConverter.FromVtq(vtq); dv.Value.ShouldBe(arr); } /// /// Confirms that integer arrays remain arrays when exposed through OPC UA. /// [Fact] public void FromVtq_IntArray() { var arr = new[] { 1, 2, 3 }; var vtq = Vtq.Good(arr); var dv = DataValueConverter.FromVtq(vtq); dv.Value.ShouldBe(arr); } /// /// Confirms that bad runtime quality is translated to a bad OPC UA status code. /// [Fact] public void FromVtq_BadQuality_MapsToStatusCode() { var vtq = Vtq.Bad(Quality.BadCommFailure); var dv = DataValueConverter.FromVtq(vtq); Opc.Ua.StatusCode.IsBad(dv.StatusCode).ShouldBe(true); } /// /// Confirms that uncertain runtime quality is translated to an uncertain OPC UA status code. /// [Fact] public void FromVtq_UncertainQuality() { var vtq = Vtq.Uncertain(42); var dv = DataValueConverter.FromVtq(vtq); Opc.Ua.StatusCode.IsUncertain(dv.StatusCode).ShouldBe(true); } /// /// Confirms that null runtime values remain null when converted for OPC UA. /// [Fact] public void FromVtq_NullValue() { var vtq = Vtq.Good(null); var dv = DataValueConverter.FromVtq(vtq); dv.Value.ShouldBeNull(); } /// /// Confirms that a data value can round-trip back into a VTQ without losing the process value or quality. /// [Fact] public void ToVtq_RoundTrip() { var original = new Vtq(42, DateTime.UtcNow, Quality.Good); var dv = DataValueConverter.FromVtq(original); var roundTrip = DataValueConverter.ToVtq(dv); roundTrip.Value.ShouldBe(42); roundTrip.Quality.ShouldBe(Quality.Good); } } }