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 { /// /// Verifies the in-memory address-space model built from Galaxy hierarchy and attribute rows. /// public class LmxNodeManagerBuildTests { /// /// Creates representative Galaxy hierarchy and attribute rows for address-space builder tests. /// /// The hierarchy and attribute rows used by the tests. private static (List hierarchy, List attributes) CreateTestData() { var hierarchy = new List { new GalaxyObjectInfo { GobjectId = 1, TagName = "DEV", ContainedName = "DEV", BrowseName = "DEV", ParentGobjectId = 0, IsArea = true }, new GalaxyObjectInfo { GobjectId = 2, TagName = "TestArea", ContainedName = "TestArea", BrowseName = "TestArea", ParentGobjectId = 1, IsArea = true }, new GalaxyObjectInfo { GobjectId = 3, TagName = "TestMachine_001", ContainedName = "TestMachine_001", BrowseName = "TestMachine_001", ParentGobjectId = 2, IsArea = false }, new GalaxyObjectInfo { GobjectId = 4, TagName = "DelmiaReceiver_001", ContainedName = "DelmiaReceiver", BrowseName = "DelmiaReceiver", ParentGobjectId = 3, IsArea = false }, }; var attributes = new List { new GalaxyAttributeInfo { GobjectId = 3, TagName = "TestMachine_001", AttributeName = "MachineID", FullTagReference = "TestMachine_001.MachineID", MxDataType = 5, IsArray = false }, new GalaxyAttributeInfo { GobjectId = 4, TagName = "DelmiaReceiver_001", AttributeName = "DownloadPath", FullTagReference = "DelmiaReceiver_001.DownloadPath", MxDataType = 5, IsArray = false }, new GalaxyAttributeInfo { GobjectId = 4, TagName = "DelmiaReceiver_001", AttributeName = "JobStepNumber", FullTagReference = "DelmiaReceiver_001.JobStepNumber", MxDataType = 2, IsArray = false }, new GalaxyAttributeInfo { GobjectId = 3, TagName = "TestMachine_001", AttributeName = "BatchItems", FullTagReference = "TestMachine_001.BatchItems[]", MxDataType = 5, IsArray = true, ArrayDimension = 50 }, }; return (hierarchy, attributes); } /// /// Confirms that object and variable counts are computed correctly from the seeded Galaxy model. /// [Fact] public void BuildAddressSpace_CreatesCorrectNodeCounts() { var (hierarchy, attributes) = CreateTestData(); var model = AddressSpaceBuilder.Build(hierarchy, attributes); model.ObjectCount.ShouldBe(2); // TestMachine_001, DelmiaReceiver model.VariableCount.ShouldBe(4); // MachineID, DownloadPath, JobStepNumber, BatchItems } /// /// Confirms that runtime tag references are populated for every published variable. /// [Fact] public void BuildAddressSpace_TagReferencesPopulated() { var (hierarchy, attributes) = CreateTestData(); var model = AddressSpaceBuilder.Build(hierarchy, attributes); model.NodeIdToTagReference.ContainsKey("TestMachine_001.MachineID").ShouldBe(true); model.NodeIdToTagReference.ContainsKey("DelmiaReceiver_001.DownloadPath").ShouldBe(true); model.NodeIdToTagReference.ContainsKey("DelmiaReceiver_001.JobStepNumber").ShouldBe(true); model.NodeIdToTagReference.ContainsKey("TestMachine_001.BatchItems").ShouldBe(true); } /// /// Confirms that array attributes are represented in the tag-reference map. /// [Fact] public void BuildAddressSpace_ArrayVariable_HasCorrectInfo() { var (hierarchy, attributes) = CreateTestData(); var model = AddressSpaceBuilder.Build(hierarchy, attributes); model.NodeIdToTagReference.ContainsKey("TestMachine_001.BatchItems").ShouldBe(true); model.NodeIdToTagReference["TestMachine_001.BatchItems"].ShouldBe("TestMachine_001.BatchItems[]"); } /// /// Confirms that Galaxy areas are not counted as object nodes in the resulting model. /// [Fact] public void BuildAddressSpace_Areas_AreNotCountedAsObjects() { var hierarchy = new List { new GalaxyObjectInfo { GobjectId = 1, TagName = "Area1", BrowseName = "Area1", ParentGobjectId = 0, IsArea = true }, new GalaxyObjectInfo { GobjectId = 2, TagName = "Obj1", BrowseName = "Obj1", ParentGobjectId = 1, IsArea = false } }; var model = AddressSpaceBuilder.Build(hierarchy, new List()); model.ObjectCount.ShouldBe(1); // Only Obj1, not Area1 } /// /// Confirms that only top-level Galaxy nodes are returned as roots in the model. /// [Fact] public void BuildAddressSpace_RootNodes_AreTopLevel() { var hierarchy = new List { new GalaxyObjectInfo { GobjectId = 1, TagName = "Root1", BrowseName = "Root1", ParentGobjectId = 0, IsArea = true }, new GalaxyObjectInfo { GobjectId = 2, TagName = "Child1", BrowseName = "Child1", ParentGobjectId = 1, IsArea = false } }; var model = AddressSpaceBuilder.Build(hierarchy, new List()); model.RootNodes.Count.ShouldBe(1); // Only Root1 is a root } /// /// Confirms that variables for multiple MX data types are included in the model. /// [Fact] public void BuildAddressSpace_DataTypeMappings() { var hierarchy = new List { new GalaxyObjectInfo { GobjectId = 1, TagName = "Obj", BrowseName = "Obj", ParentGobjectId = 0, IsArea = false } }; var attributes = new List { new GalaxyAttributeInfo { GobjectId = 1, TagName = "Obj", AttributeName = "BoolAttr", FullTagReference = "Obj.BoolAttr", MxDataType = 1, IsArray = false }, new GalaxyAttributeInfo { GobjectId = 1, TagName = "Obj", AttributeName = "IntAttr", FullTagReference = "Obj.IntAttr", MxDataType = 2, IsArray = false }, new GalaxyAttributeInfo { GobjectId = 1, TagName = "Obj", AttributeName = "FloatAttr", FullTagReference = "Obj.FloatAttr", MxDataType = 3, IsArray = false }, new GalaxyAttributeInfo { GobjectId = 1, TagName = "Obj", AttributeName = "StrAttr", FullTagReference = "Obj.StrAttr", MxDataType = 5, IsArray = false }, }; var model = AddressSpaceBuilder.Build(hierarchy, attributes); model.VariableCount.ShouldBe(4); model.NodeIdToTagReference.Count.ShouldBe(4); } } }