using System.Collections.Generic; using Shouldly; using Xunit; using ZB.MOM.WW.LmxOpcUa.Host.Domain; using ZB.MOM.WW.LmxOpcUa.Host.OpcUa; namespace ZB.MOM.WW.LmxOpcUa.Tests.OpcUa { public class AddressSpaceDiffTests { private static GalaxyObjectInfo Obj(int id, string tag, int parent = 0, bool isArea = false) => new GalaxyObjectInfo { GobjectId = id, TagName = tag, BrowseName = tag, ContainedName = tag, ParentGobjectId = parent, IsArea = isArea }; private static GalaxyAttributeInfo Attr(int gobjectId, string name, string tagName = "Obj", int mxDataType = 5) => new GalaxyAttributeInfo { GobjectId = gobjectId, AttributeName = name, FullTagReference = $"{tagName}.{name}", MxDataType = mxDataType, TagName = tagName }; [Fact] public void NoChanges_ReturnsEmptySet() { var h = new List { Obj(1, "A") }; var a = new List { Attr(1, "X") }; var changed = AddressSpaceDiff.FindChangedGobjectIds(h, a, h, a); changed.ShouldBeEmpty(); } [Fact] public void AddedObject_Detected() { var oldH = new List { Obj(1, "A") }; var newH = new List { Obj(1, "A"), Obj(2, "B") }; var a = new List(); var changed = AddressSpaceDiff.FindChangedGobjectIds(oldH, a, newH, a); changed.ShouldContain(2); changed.ShouldNotContain(1); } [Fact] public void RemovedObject_Detected() { var oldH = new List { Obj(1, "A"), Obj(2, "B") }; var newH = new List { Obj(1, "A") }; var a = new List(); var changed = AddressSpaceDiff.FindChangedGobjectIds(oldH, a, newH, a); changed.ShouldContain(2); changed.ShouldNotContain(1); } [Fact] public void ModifiedObject_BrowseNameChange_Detected() { var oldH = new List { Obj(1, "A") }; var newH = new List { new GalaxyObjectInfo { GobjectId = 1, TagName = "A", BrowseName = "A_Renamed", ContainedName = "A" } }; var a = new List(); var changed = AddressSpaceDiff.FindChangedGobjectIds(oldH, a, newH, a); changed.ShouldContain(1); } [Fact] public void ModifiedObject_ParentChange_Detected() { var oldH = new List { Obj(1, "A"), Obj(2, "B", parent: 1) }; var newH = new List { Obj(1, "A"), new GalaxyObjectInfo { GobjectId = 2, TagName = "B", BrowseName = "B", ContainedName = "B", ParentGobjectId = 0 } }; var a = new List(); var changed = AddressSpaceDiff.FindChangedGobjectIds(oldH, a, newH, a); changed.ShouldContain(2); } [Fact] public void AttributeAdded_Detected() { var h = new List { Obj(1, "A") }; var oldA = new List { Attr(1, "X") }; var newA = new List { Attr(1, "X"), Attr(1, "Y") }; var changed = AddressSpaceDiff.FindChangedGobjectIds(h, oldA, h, newA); changed.ShouldContain(1); } [Fact] public void AttributeRemoved_Detected() { var h = new List { Obj(1, "A") }; var oldA = new List { Attr(1, "X"), Attr(1, "Y") }; var newA = new List { Attr(1, "X") }; var changed = AddressSpaceDiff.FindChangedGobjectIds(h, oldA, h, newA); changed.ShouldContain(1); } [Fact] public void AttributeFieldChange_Detected() { var h = new List { Obj(1, "A") }; var oldA = new List { Attr(1, "X", mxDataType: 5) }; var newA = new List { Attr(1, "X", mxDataType: 2) }; var changed = AddressSpaceDiff.FindChangedGobjectIds(h, oldA, h, newA); changed.ShouldContain(1); } [Fact] public void AttributeSecurityChange_Detected() { var h = new List { Obj(1, "A") }; var oldA = new List { new GalaxyAttributeInfo { GobjectId = 1, AttributeName = "X", FullTagReference = "A.X", SecurityClassification = 1 } }; var newA = new List { new GalaxyAttributeInfo { GobjectId = 1, AttributeName = "X", FullTagReference = "A.X", SecurityClassification = 2 } }; var changed = AddressSpaceDiff.FindChangedGobjectIds(h, oldA, h, newA); changed.ShouldContain(1); } [Fact] public void ExpandToSubtrees_IncludesChildren() { var h = new List { Obj(1, "Root"), Obj(2, "Child", parent: 1), Obj(3, "Grandchild", parent: 2), Obj(4, "Sibling", parent: 1), Obj(5, "Unrelated") }; var changed = new HashSet { 1 }; var expanded = AddressSpaceDiff.ExpandToSubtrees(changed, h); expanded.ShouldContain(1); expanded.ShouldContain(2); expanded.ShouldContain(3); expanded.ShouldContain(4); expanded.ShouldNotContain(5); } [Fact] public void ExpandToSubtrees_LeafNode_NoExpansion() { var h = new List { Obj(1, "Root"), Obj(2, "Child", parent: 1), Obj(3, "Sibling", parent: 1) }; var changed = new HashSet { 2 }; var expanded = AddressSpaceDiff.ExpandToSubtrees(changed, h); expanded.ShouldContain(2); expanded.ShouldNotContain(1); expanded.ShouldNotContain(3); } } }