using System; using MessagePack; using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Shared.Contracts; namespace ZB.MOM.WW.OtOpcUa.Driver.Galaxy.Host.Tests; [Trait("Category", "Unit")] public sealed class AlarmDiscoveryTests { /// /// PR 9 — IsAlarm must survive the MessagePack round-trip at Key=6 position. /// Regression guard: any reorder of keys in GalaxyAttributeInfo would silently corrupt /// the flag in the wire payload since MessagePack encodes by key number, not field name. /// [Fact] public void GalaxyAttributeInfo_IsAlarm_round_trips_true_through_MessagePack() { var input = new GalaxyAttributeInfo { AttributeName = "TankLevel", MxDataType = 2, IsArray = false, ArrayDim = null, SecurityClassification = 1, IsHistorized = true, IsAlarm = true, }; var bytes = MessagePackSerializer.Serialize(input); var decoded = MessagePackSerializer.Deserialize(bytes); decoded.IsAlarm.ShouldBeTrue(); decoded.IsHistorized.ShouldBeTrue(); decoded.AttributeName.ShouldBe("TankLevel"); } [Fact] public void GalaxyAttributeInfo_IsAlarm_round_trips_false_through_MessagePack() { var input = new GalaxyAttributeInfo { AttributeName = "ColorRgb", IsAlarm = false }; var bytes = MessagePackSerializer.Serialize(input); var decoded = MessagePackSerializer.Deserialize(bytes); decoded.IsAlarm.ShouldBeFalse(); } /// /// Wire-compat guard: payloads serialized before PR 9 (which omit Key=6) must still /// deserialize cleanly — MessagePack treats missing keys as default. This lets a newer /// Proxy talk to an older Host during a rolling upgrade without a crash. /// [Fact] public void Pre_PR9_payload_without_IsAlarm_key_deserializes_with_default_false() { // Build a 6-field payload (keys 0..5) matching the pre-PR9 shape by serializing a // stand-in class with the same key layout but no Key=6. var pre = new PrePR9Shape { AttributeName = "Legacy", MxDataType = 1, IsArray = false, ArrayDim = null, SecurityClassification = 0, IsHistorized = false, }; var bytes = MessagePackSerializer.Serialize(pre); var decoded = MessagePackSerializer.Deserialize(bytes); decoded.AttributeName.ShouldBe("Legacy"); decoded.IsAlarm.ShouldBeFalse(); } [MessagePackObject] public sealed class PrePR9Shape { [Key(0)] public string AttributeName { get; set; } = string.Empty; [Key(1)] public int MxDataType { get; set; } [Key(2)] public bool IsArray { get; set; } [Key(3)] public uint? ArrayDim { get; set; } [Key(4)] public int SecurityClassification { get; set; } [Key(5)] public bool IsHistorized { get; set; } } }