using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.AdminUI.Uns; namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns; public sealed class UnsTreeAssemblyTests { [Fact] public void Build_groups_clusters_under_enterprise() { var clusters = new[] { new ClusterRow("c1", "zb", "SiteA", "Alpha"), new ClusterRow("c2", "zb", "SiteB", "Bravo"), }; var tree = UnsTreeAssembly.Build( clusters, areas: System.Array.Empty(), lines: System.Array.Empty(), equipment: System.Array.Empty()); tree.Count.ShouldBe(1); var ent = tree[0]; ent.Kind.ShouldBe(UnsNodeKind.Enterprise); ent.Key.ShouldBe("ent:zb"); ent.DisplayName.ShouldBe("zb"); ent.Children.Count.ShouldBe(2); ent.Children.All(c => c.Kind == UnsNodeKind.Cluster).ShouldBeTrue(); ent.Children.Select(c => c.Key).ShouldBe(new[] { "clu:c1", "clu:c2" }); } [Fact] public void Build_nests_area_line_equipment_under_owning_cluster() { var clusters = new[] { new ClusterRow("c1", "zb", "SiteA", "Alpha") }; var areas = new[] { new AreaRow("a1", "c1", "AreaOne") }; var lines = new[] { new LineRow("l1", "a1", "LineOne") }; var equipment = new[] { new EquipmentRow("e1", "l1", "MC-1", "EquipOne", 0, 0) }; var tree = UnsTreeAssembly.Build(clusters, areas, lines, equipment); var cluster = tree.Single().Children.Single(); cluster.Key.ShouldBe("clu:c1"); cluster.EntityId.ShouldBe("c1"); var area = cluster.Children.Single(); area.Kind.ShouldBe(UnsNodeKind.Area); area.Key.ShouldBe("area:a1"); area.DisplayName.ShouldBe("AreaOne"); area.ClusterId.ShouldBe("c1"); area.EntityId.ShouldBe("a1"); var line = area.Children.Single(); line.Kind.ShouldBe(UnsNodeKind.Line); line.Key.ShouldBe("line:l1"); line.DisplayName.ShouldBe("LineOne"); line.ClusterId.ShouldBe("c1"); line.EntityId.ShouldBe("l1"); var eq = line.Children.Single(); eq.Kind.ShouldBe(UnsNodeKind.Equipment); eq.Key.ShouldBe("eq:e1"); eq.DisplayName.ShouldBe("EquipOne"); eq.ClusterId.ShouldBe("c1"); eq.EntityId.ShouldBe("e1"); } [Fact] public void Build_sets_equipment_child_count_and_lazy_flag() { var clusters = new[] { new ClusterRow("c1", "zb", "SiteA", "Alpha") }; var areas = new[] { new AreaRow("a1", "c1", "AreaOne") }; var lines = new[] { new LineRow("l1", "a1", "LineOne") }; var equipment = new[] { new EquipmentRow("e1", "l1", "MC-1", "WithChildren", 2, 1), new EquipmentRow("e2", "l1", "MC-2", "Empty", 0, 0), }; var tree = UnsTreeAssembly.Build(clusters, areas, lines, equipment); var line = tree.Single().Children.Single().Children.Single().Children.Single(); var withChildren = line.Children.Single(e => e.Key == "eq:e1"); withChildren.ChildCount.ShouldBe(3); withChildren.HasLazyChildren.ShouldBeTrue(); var empty = line.Children.Single(e => e.Key == "eq:e2"); empty.ChildCount.ShouldBe(0); empty.HasLazyChildren.ShouldBeFalse(); } [Fact] public void Build_includes_clusters_with_no_areas() { var clusters = new[] { new ClusterRow("c1", "zb", "SiteA", "Alpha"), new ClusterRow("c2", "zb", "SiteB", "Bravo"), }; var areas = new[] { new AreaRow("a1", "c1", "AreaOne") }; var tree = UnsTreeAssembly.Build( clusters, areas, lines: System.Array.Empty(), equipment: System.Array.Empty()); var ent = tree.Single(); ent.Children.Count.ShouldBe(2); var emptyCluster = ent.Children.Single(c => c.Key == "clu:c2"); emptyCluster.Children.ShouldBeEmpty(); var populatedCluster = ent.Children.Single(c => c.Key == "clu:c1"); populatedCluster.Children.Single().Key.ShouldBe("area:a1"); } [Fact] public void Build_orders_deterministically() { // Two enterprises out of order; clusters/areas/lines/equipment scrambled. // Two clusters with identical Name but different ClusterId to verify tie-break ordering. var clusters = new[] { new ClusterRow("cZ", "zeta", "SiteZ", "Zeta"), new ClusterRow("c9", "zeta", "SiteZ", "Zeta"), new ClusterRow("c8", "zeta", "SiteZ", "Zeta"), new ClusterRow("c2", "alpha", "Site2", "Bravo"), new ClusterRow("c1", "alpha", "Site1", "Alpha"), }; var areas = new[] { new AreaRow("a2", "c1", "Beta"), new AreaRow("a1", "c1", "Alpha"), }; var lines = new[] { new LineRow("l2", "a1", "LineB"), new LineRow("l1", "a1", "LineA"), }; var equipment = new[] { new EquipmentRow("e2", "l1", "MC-2", "EquipB", 0, 0), new EquipmentRow("e1", "l1", "MC-1", "EquipA", 0, 0), }; var tree = UnsTreeAssembly.Build(clusters, areas, lines, equipment); // Enterprises ordered by Enterprise (ordinal): "alpha" < "zeta". tree.Select(e => e.Key).ShouldBe(new[] { "ent:alpha", "ent:zeta" }); // Clusters under "alpha" ordered by Name then ClusterId: "Alpha"(c1) < "Bravo"(c2). var alphaEnt = tree.Single(e => e.Key == "ent:alpha"); alphaEnt.Children.Select(c => c.Key).ShouldBe(new[] { "clu:c1", "clu:c2" }); // Areas ordered by Name then UnsAreaId: "Alpha"(a1) < "Beta"(a2). var c1 = alphaEnt.Children.Single(c => c.Key == "clu:c1"); c1.Children.Select(a => a.Key).ShouldBe(new[] { "area:a1", "area:a2" }); // Lines under a1 ordered by Name then UnsLineId: "LineA"(l1) < "LineB"(l2). var a1 = c1.Children.Single(a => a.Key == "area:a1"); a1.Children.Select(l => l.Key).ShouldBe(new[] { "line:l1", "line:l2" }); // Equipment under l1 ordered by Name then EquipmentId: "EquipA"(e1) < "EquipB"(e2). var l1 = a1.Children.Single(l => l.Key == "line:l1"); l1.Children.Select(eq => eq.Key).ShouldBe(new[] { "eq:e1", "eq:e2" }); // Clusters with the same Name tie-break by ClusterId ordinal: "c8" < "c9" < "cZ". var zetaEnt = tree.Single(e => e.Key == "ent:zeta"); zetaEnt.Children.Select(c => c.Key).ShouldBe(new[] { "clu:c8", "clu:c9", "clu:cZ" }); } }