using ZB.MOM.WW.ScadaBridge.Commons.Messages.Streaming; using ZB.MOM.WW.ScadaBridge.Commons.Types.Alarms; using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums; namespace ZB.MOM.WW.ScadaBridge.Commons.Tests.Messages; public class AlarmStateChangedEnrichmentTests { [Fact] public void Defaults_AreComputedKind_WithAutoAck() { var m = new AlarmStateChanged("inst", "HiAlarm", AlarmState.Active, 700, DateTimeOffset.UnixEpoch); Assert.Equal(AlarmKind.Computed, m.Kind); Assert.True(m.Condition.Acknowledged); // computed = auto-acked Assert.Equal(700, m.Condition.Severity); // severity defaults to Priority Assert.True(m.Condition.Active); // derived from State Assert.Equal("", m.SourceReference); } [Fact] public void Factory_ForComputed_MapsPriorityAndState() { var c = AlarmConditionStateFactory.ForComputed(AlarmState.Normal, priority: 250); Assert.False(c.Active); Assert.True(c.Acknowledged); Assert.Equal(250, c.Severity); } // ── MES alarm-status API §6.4: additive AckTime ── [Fact] public void AckTime_DefaultsToNull_OnThePositionalConstructor() { // Additive-only evolution: every existing positional construction stays valid and // reports no ack time. A computed alarm is auto-acked but has no operator ack // event, so null (not the timestamp) is the honest value. var m = new AlarmStateChanged("inst", "HiAlarm", AlarmState.Active, 700, DateTimeOffset.UnixEpoch); Assert.True(m.Condition.Acknowledged); // computed = auto-acked… Assert.Null(m.AckTime); // …yet still no ack instant } [Fact] public void AckTime_RoundTripsThroughTheInitProperty() { var ackedAt = new DateTimeOffset(2026, 8, 1, 12, 0, 0, TimeSpan.Zero); var m = new AlarmStateChanged("inst", "Tank01.Level.HiHi", AlarmState.Active, 900, DateTimeOffset.UnixEpoch) { Kind = AlarmKind.NativeOpcUa, AckTime = ackedAt }; Assert.Equal(ackedAt, m.AckTime); // `with` (used by the mirror to synthesise a return-to-normal) preserves it. Assert.Equal(ackedAt, (m with { State = AlarmState.Normal }).AckTime); } }