using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors; namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns; /// /// Round-trip tests for the native-alarm sub-model's historizeToAveva opt-out /// (the TagConfig.alarm.historizeToAveva bool?). Absent ⇒ null ⇒ the server's /// HistorianAdapterActor "is not false" gate still historizes (default-on); explicit /// false suppresses the durable AVEVA write. Mirrors the scripted-alarm opt-out posture. /// public sealed class NativeAlarmHistorizeModelTests { [Fact] public void FromJson_no_alarm_object_means_not_an_alarm_tag() { var m = NativeAlarmModel.FromJson("""{"FullName":"Temp.HiHi"}"""); m.IsAlarm.ShouldBeFalse(); m.HistorizeToAveva.ShouldBeNull(); } [Theory] [InlineData(null)] [InlineData("")] [InlineData(" ")] [InlineData("{}")] public void FromJson_returns_non_alarm_for_empty_input(string? json) { var m = NativeAlarmModel.FromJson(json); m.IsAlarm.ShouldBeFalse(); m.HistorizeToAveva.ShouldBeNull(); } [Fact] public void FromJson_alarm_without_historizeToAveva_is_null_default_on() { var m = NativeAlarmModel.FromJson( """{"FullName":"Temp.HiHi","alarm":{"alarmType":"OffNormalAlarm","severity":700}}"""); m.IsAlarm.ShouldBeTrue(); m.AlarmType.ShouldBe("OffNormalAlarm"); m.Severity.ShouldBe(700); // Absent ⇒ null ⇒ historize (default-on at the gate). m.HistorizeToAveva.ShouldBeNull(); } [Fact] public void FromJson_reads_historizeToAveva_true() { var m = NativeAlarmModel.FromJson( """{"alarm":{"alarmType":"LimitAlarm","severity":500,"historizeToAveva":true}}"""); m.HistorizeToAveva.ShouldBe(true); } [Fact] public void FromJson_reads_historizeToAveva_false_opt_out() { var m = NativeAlarmModel.FromJson( """{"alarm":{"alarmType":"LimitAlarm","severity":500,"historizeToAveva":false}}"""); m.HistorizeToAveva.ShouldBe(false); } [Fact] public void Round_trip_true_persists_true() { var m = NativeAlarmModel.FromJson( """{"alarm":{"alarmType":"LimitAlarm","severity":500}}"""); m.HistorizeToAveva = true; var round = NativeAlarmModel.FromJson(m.ToJson()); round.HistorizeToAveva.ShouldBe(true); round.IsAlarm.ShouldBeTrue(); } [Fact] public void Round_trip_false_persists_false() { var m = NativeAlarmModel.FromJson( """{"alarm":{"alarmType":"LimitAlarm","severity":500}}"""); m.HistorizeToAveva = false; var round = NativeAlarmModel.FromJson(m.ToJson()); round.HistorizeToAveva.ShouldBe(false); } [Fact] public void Round_trip_null_omits_the_key_default_on() { var m = NativeAlarmModel.FromJson( """{"alarm":{"alarmType":"LimitAlarm","severity":500,"historizeToAveva":true}}"""); m.HistorizeToAveva = null; var json = m.ToJson(); json.ShouldNotContain("historizeToAveva"); NativeAlarmModel.FromJson(json).HistorizeToAveva.ShouldBeNull(); } [Fact] public void ToJson_preserves_unknown_keys_at_root_and_in_alarm() { var m = NativeAlarmModel.FromJson( """{"FullName":"Temp.HiHi","alarm":{"alarmType":"OffNormalAlarm","severity":700,"customAlarmKey":"keep-me"},"customRootKey":42}"""); m.HistorizeToAveva = false; var json = m.ToJson(); json.ShouldContain("FullName"); json.ShouldContain("Temp.HiHi"); json.ShouldContain("customRootKey"); json.ShouldContain("customAlarmKey"); json.ShouldContain("keep-me"); json.ShouldContain("historizeToAveva"); } }