using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Core.Abstractions; namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests.Alarms; /// /// Contract tests for the record extension added in PR 2.1. /// Five sub-attribute references (InAlarmRef, PriorityRef, DescAttrNameRef, AckedRef, /// AckMsgWriteRef) carry the driver-side tag references the server-level alarm-condition /// service uses to subscribe to live alarm-state attributes and route ack writes. /// public sealed class AlarmConditionInfoTests { [Fact] public void LegacyThreeArgConstructor_StillCompiles_AndDefaultsRefsToNull() { var info = new AlarmConditionInfo( SourceName: "Tank.HiHi", InitialSeverity: AlarmSeverity.High, InitialDescription: "High-high alarm"); info.SourceName.ShouldBe("Tank.HiHi"); info.InitialSeverity.ShouldBe(AlarmSeverity.High); info.InitialDescription.ShouldBe("High-high alarm"); info.InAlarmRef.ShouldBeNull(); info.PriorityRef.ShouldBeNull(); info.DescAttrNameRef.ShouldBeNull(); info.AckedRef.ShouldBeNull(); info.AckMsgWriteRef.ShouldBeNull(); } [Fact] public void FullConstructor_PopulatesAllFiveSubAttributeRefs() { var info = new AlarmConditionInfo( SourceName: "Tank1.HiAlarm", InitialSeverity: AlarmSeverity.Medium, InitialDescription: "Tank level high", InAlarmRef: "Tank1.HiAlarm.InAlarm", PriorityRef: "Tank1.HiAlarm.Priority", DescAttrNameRef: "Tank1.HiAlarm.DescAttrName", AckedRef: "Tank1.HiAlarm.Acked", AckMsgWriteRef: "Tank1.HiAlarm.AckMsg"); info.InAlarmRef.ShouldBe("Tank1.HiAlarm.InAlarm"); info.PriorityRef.ShouldBe("Tank1.HiAlarm.Priority"); info.DescAttrNameRef.ShouldBe("Tank1.HiAlarm.DescAttrName"); info.AckedRef.ShouldBe("Tank1.HiAlarm.Acked"); info.AckMsgWriteRef.ShouldBe("Tank1.HiAlarm.AckMsg"); } [Fact] public void RecordEquality_ComparesAllEightFields() { var a = new AlarmConditionInfo( "T.Alarm", AlarmSeverity.Low, "desc", "T.Alarm.InAlarm", "T.Alarm.Priority", "T.Alarm.DescAttrName", "T.Alarm.Acked", "T.Alarm.AckMsg"); var b = new AlarmConditionInfo( "T.Alarm", AlarmSeverity.Low, "desc", "T.Alarm.InAlarm", "T.Alarm.Priority", "T.Alarm.DescAttrName", "T.Alarm.Acked", "T.Alarm.AckMsg"); a.ShouldBe(b); } [Fact] public void RecordEquality_DistinctWhenAnyRefDiffers() { var baseInfo = new AlarmConditionInfo( "T.Alarm", AlarmSeverity.Low, "desc", InAlarmRef: "T.Alarm.InAlarm"); var differingAckRef = baseInfo with { AckedRef = "T.Alarm.Acked" }; baseInfo.ShouldNotBe(differingAckRef); } [Fact] public void WithExpression_AllowsPartialUpdates() { var legacy = new AlarmConditionInfo("S", AlarmSeverity.Medium, null); var enriched = legacy with { InAlarmRef = "S.InAlarm", AckedRef = "S.Acked", AckMsgWriteRef = "S.AckMsg", }; enriched.SourceName.ShouldBe("S"); enriched.InAlarmRef.ShouldBe("S.InAlarm"); enriched.PriorityRef.ShouldBeNull(); enriched.DescAttrNameRef.ShouldBeNull(); enriched.AckedRef.ShouldBe("S.Acked"); enriched.AckMsgWriteRef.ShouldBe("S.AckMsg"); } }