using ZB.MOM.WW.MxGateway.Client; using ZB.MOM.WW.MxGateway.Contracts.Proto; using ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Adapters; using CommonsTransitionKind = ZB.MOM.WW.ScadaBridge.Commons.Types.Enums.AlarmTransitionKind; using ProtoConditionState = ZB.MOM.WW.MxGateway.Contracts.Proto.AlarmConditionState; using ProtoTransitionKind = ZB.MOM.WW.MxGateway.Contracts.Proto.AlarmTransitionKind; namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests; /// Task-12: pure MxGateway alarm-feed proto → NativeAlarmTransition mapping. public class MxGatewayAlarmMapperTests { [Fact] public void MapTransition_AckTransition_IsAcknowledgedWithOperator() { var ev = new OnAlarmTransitionEvent { AlarmFullReference = "Tank01.Level.HiHi", SourceObjectReference = "Tank01", AlarmTypeName = "AnalogLimitAlarm.HiHi", TransitionKind = ProtoTransitionKind.Acknowledge, Severity = 600, OperatorUser = "operator1", OperatorComment = "ack", Category = "Process", Description = "hi" }; var t = MxGatewayAlarmMapper.MapTransition(ev); Assert.Equal(CommonsTransitionKind.Acknowledge, t.Kind); Assert.True(t.Condition.Active); Assert.True(t.Condition.Acknowledged); Assert.Equal(600, t.Condition.Severity); Assert.Equal("operator1", t.OperatorUser); Assert.Equal("Tank01", t.SourceObjectReference); } [Fact] public void MapConditionState_ActiveAcked_To_ActiveTrue_AckTrue() { var c = MxGatewayAlarmMapper.MapConditionState(ProtoConditionState.ActiveAcked, severity: 600); Assert.True(c.Active); Assert.True(c.Acknowledged); Assert.Equal(600, c.Severity); } [Fact] public void MapSnapshot_ActiveUnacked_IsSnapshotKind() { var snap = new ActiveAlarmSnapshot { AlarmFullReference = "Tank01.Level.Hi", SourceObjectReference = "Tank01", AlarmTypeName = "AnalogLimitAlarm.Hi", CurrentState = ProtoConditionState.Active, Severity = 1500 // out of range — must clamp }; var t = MxGatewayAlarmMapper.MapSnapshot(snap); Assert.Equal(CommonsTransitionKind.Snapshot, t.Kind); Assert.True(t.Condition.Active); Assert.False(t.Condition.Acknowledged); Assert.Equal(1000, t.Condition.Severity); } // ── CurrentValue / LimitValue (M2.13 / #27) ────────────────────────────── [Fact] public void MapTransition_CurrentAndLimitValue_PopulatedFromProto() { // The gateway proto OnAlarmTransitionEvent carries current_value and // limit_value as MxValue union fields. Verify both are mapped through // MxValueToString into the neutral NativeAlarmTransition strings. var ev = new OnAlarmTransitionEvent { AlarmFullReference = "Tank01.Level.HiHi", SourceObjectReference = "Tank01", AlarmTypeName = "AnalogLimitAlarm.HiHi", TransitionKind = ProtoTransitionKind.Raise, Severity = 800, CurrentValue = 95.3.ToMxValue(), LimitValue = 90.0.ToMxValue() }; var t = MxGatewayAlarmMapper.MapTransition(ev); Assert.Equal("95.3", t.CurrentValue); Assert.Equal("90", t.LimitValue); } [Fact] public void MapTransition_AbsentCurrentAndLimitValue_YieldsEmpty() { // When the gateway sends events without current/limit value fields (optional), // the resulting transition must have empty strings — never null. var ev = new OnAlarmTransitionEvent { AlarmFullReference = "Tank01.Level.Hi", SourceObjectReference = "Tank01", AlarmTypeName = "AnalogLimitAlarm.Hi", TransitionKind = ProtoTransitionKind.Raise, Severity = 600 // CurrentValue and LimitValue not set → proto default (null reference) }; var t = MxGatewayAlarmMapper.MapTransition(ev); Assert.Equal("", t.CurrentValue); Assert.Equal("", t.LimitValue); } [Fact] public void MapSnapshot_CurrentAndLimitValue_PopulatedFromProto() { // ActiveAlarmSnapshot also carries current_value and limit_value. var snap = new ActiveAlarmSnapshot { AlarmFullReference = "Pump01.Vibration.HiHi", SourceObjectReference = "Pump01", AlarmTypeName = "AnalogLimitAlarm.HiHi", CurrentState = ProtoConditionState.Active, Severity = 900, CurrentValue = 12.7.ToMxValue(), LimitValue = 10.0.ToMxValue() }; var t = MxGatewayAlarmMapper.MapSnapshot(snap); Assert.Equal("12.7", t.CurrentValue); Assert.Equal("10", t.LimitValue); } [Fact] public void MapSnapshot_StringMxValue_ProducesStringCurrentValue() { // MxValue can carry string values (e.g. for discrete/string-type tags). var snap = new ActiveAlarmSnapshot { AlarmFullReference = "Mode.Alarm", SourceObjectReference = "Mode", AlarmTypeName = "DiscreteAlarm", CurrentState = ProtoConditionState.Active, Severity = 500, CurrentValue = "FAULT".ToMxValue() }; var t = MxGatewayAlarmMapper.MapSnapshot(snap); Assert.Equal("FAULT", t.CurrentValue); Assert.Equal("", t.LimitValue); // not set } }