Files
ScadaBridge/tests/ZB.MOM.WW.ScadaBridge.CentralUI.Tests/Shared/InstanceTreeBuilderTests.cs
T
Joseph Doherty 513fa1aa16 docs(tests): fix CommentChecker findings across tests/ — 13,392 → 0 (repo-wide scan clean)
Comment/XML-doc changes only:
- add summaries to ~10k test methods, fixtures, fakes and helpers
  (+ <param> on theories, <returns> on async Task methods,
  <inheritdoc/> on interface implementations the checker can resolve)
- strip ~2.6k project-tracking references (WP*, P*-*, row-NN, Task N,
  #NN, Component-0NN) from comments, keeping the explanatory text;
  reword false positives in comments only
- real docs on fakes implementing BCL/library interfaces
  (IDisposable, ILogger, IOptionsMonitor, IAsyncLifetime)
- reword the last 5 src/ false positives (CWE-1236, failures-1,
  year-0001, M365)

Only non-comment edits: four one-line nested classes split across lines
so members can carry docs. Build 0 errors / 0 warnings.
2026-10-07 15:05:49 -04:00

234 lines
9.4 KiB
C#

using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Shared;
using ZB.MOM.WW.ScadaBridge.Commons.Entities.Instances;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Shared;
/// <summary>
/// Unit tests for <see cref="InstanceTreeBuilder"/> — the pure area/instance forest
/// behind the Instance Picker combobox (design 2026-09-08).
/// </summary>
public class InstanceTreeBuilderTests
{
private static Area MakeArea(int id, string name, int? parentAreaId = null) =>
new(name) { Id = id, SiteId = 1, ParentAreaId = parentAreaId };
private static Instance MakeInstance(int id, string uniqueName, int? areaId = null) =>
new(uniqueName) { Id = id, SiteId = 1, AreaId = areaId };
/// <summary>Verifies that areas are nested under their parents and root instances come after root areas.</summary>
[Fact]
public void Build_NestsAreasByParent_AndPutsRootInstancesAfterRootAreas()
{
var line1 = MakeArea(1, "Line1");
var cellA = MakeArea(2, "Cell A", parentAreaId: 1);
var p1 = MakeInstance(10, "P1", areaId: 2);
var zulu = MakeInstance(11, "Zulu");
var alpha = MakeInstance(12, "Alpha");
var roots = InstanceTreeBuilder.Build([line1, cellA], [p1, zulu, alpha], filter: null);
Assert.Equal(new[] { "a:1", "i:12", "i:11" }, roots.Select(n => n.Key));
var areaNode = roots[0];
Assert.Equal("Line1", areaNode.Label);
Assert.False(areaNode.IsInstance);
Assert.Same(line1, areaNode.Area);
Assert.Null(areaNode.Instance);
Assert.True(areaNode.HasChildren);
var cellNode = Assert.Single(areaNode.Children);
Assert.Equal("a:2", cellNode.Key);
Assert.Equal("Cell A", cellNode.Label);
Assert.Same(cellA, cellNode.Area);
var p1Node = Assert.Single(cellNode.Children);
Assert.Equal("i:10", p1Node.Key);
Assert.Equal("P1", p1Node.Label);
Assert.True(p1Node.IsInstance);
Assert.Same(p1, p1Node.Instance);
Assert.Null(p1Node.Area);
Assert.False(p1Node.HasChildren);
Assert.Equal("Alpha", roots[1].Label);
Assert.Same(alpha, roots[1].Instance);
Assert.Equal("Zulu", roots[2].Label);
Assert.Same(zulu, roots[2].Instance);
}
/// <summary>Verifies that areas and instances are sorted case-insensitively.</summary>
[Fact]
public void Build_SortsAreasAndInstancesCaseInsensitively()
{
var beta = MakeArea(1, "beta");
var alphaArea = MakeArea(2, "Alpha");
var zebra = MakeInstance(10, "zebra");
var apple = MakeInstance(11, "Apple");
var roots = InstanceTreeBuilder.Build([beta, alphaArea], [zebra, apple], filter: null);
Assert.Equal(new[] { "Alpha", "beta", "Apple", "zebra" }, roots.Select(n => n.Label));
}
/// <summary>Verifies that an area whose parent is missing becomes a root.</summary>
[Fact]
public void Build_OrphanedArea_BecomesARoot()
{
// ParentAreaId points at an area that is not in the supplied list.
var orphan = MakeArea(5, "Orphan", parentAreaId: 99);
var child = MakeInstance(10, "OrphanChild", areaId: 5);
var roots = InstanceTreeBuilder.Build([orphan], [child], filter: null);
var root = Assert.Single(roots);
Assert.Equal("a:5", root.Key);
var leaf = Assert.Single(root.Children);
Assert.Equal("i:10", leaf.Key);
}
/// <summary>Verifies that an instance with an unknown area surfaces at the root.</summary>
[Fact]
public void Build_InstanceWithUnknownArea_SurfacesAtRoot()
{
// AreaId points at an area that is not in the supplied list — the instance must not
// vanish; it is listed at the root like an instance with no area at all.
var line1 = MakeArea(1, "Line1");
var stranded = MakeInstance(10, "Stranded", areaId: 99);
var roots = InstanceTreeBuilder.Build([line1], [stranded], filter: null);
Assert.Equal(new[] { "a:1", "i:10" }, roots.Select(n => n.Key));
Assert.Same(stranded, roots[1].Instance);
}
/// <summary>Verifies that an instance with an unknown area can still be found by the filter.</summary>
[Fact]
public void Build_InstanceWithUnknownArea_StaysFilterable()
{
var line1 = MakeArea(1, "Line1");
var stranded = MakeInstance(10, "Stranded", areaId: 99);
var matched = InstanceTreeBuilder.Build([line1], [stranded], filter: "rand");
Assert.Equal("i:10", Assert.Single(matched).Key);
Assert.Empty(InstanceTreeBuilder.Build([line1], [stranded], filter: "nomatch"));
}
/// <summary>Verifies that deeply nested areas wire their children at every level.</summary>
[Fact]
public void Build_DeepNesting_WiresChildrenAtEveryLevel()
{
var plant = MakeArea(1, "Plant");
var line = MakeArea(2, "Line", parentAreaId: 1);
var cell = MakeArea(3, "Cell", parentAreaId: 2);
var deep = MakeInstance(10, "Deep", areaId: 3);
var roots = InstanceTreeBuilder.Build([plant, line, cell], [deep], filter: null);
var plantNode = Assert.Single(roots);
Assert.Equal("a:1", plantNode.Key);
var lineNode = Assert.Single(plantNode.Children);
Assert.Equal("a:2", lineNode.Key);
var cellNode = Assert.Single(lineNode.Children);
Assert.Equal("a:3", cellNode.Key);
var leaf = Assert.Single(cellNode.Children);
Assert.Equal("i:10", leaf.Key);
Assert.False(leaf.HasChildren);
}
/// <summary>Verifies that cyclic parent area ids neither loop forever nor throw.</summary>
[Fact]
public void Build_CyclicParentAreaIds_DoNotLoopOrThrow()
{
// A bad row pair: each area names the other as its parent. Neither is reachable
// from a root, so the forest is simply empty — and building it must terminate.
var a = MakeArea(1, "A", parentAreaId: 2);
var b = MakeArea(2, "B", parentAreaId: 1);
var inA = MakeInstance(10, "InA", areaId: 1);
var inB = MakeInstance(11, "InB", areaId: 2);
var roots = InstanceTreeBuilder.Build([a, b], [inA, inB], filter: null);
Assert.Empty(roots);
}
/// <summary>Verifies that the filter matches instance names only, so an area name match alone is not enough.</summary>
[Fact]
public void Build_Filter_MatchesInstanceNamesOnly_AreaNameMatchIsNotEnough()
{
// "Line1" contains the needle but holds no matching instance — it is dropped.
var line1 = MakeArea(1, "Line1");
var line2 = MakeArea(2, "Line2");
var other = MakeInstance(10, "Pump", areaId: 1);
var hit = MakeInstance(11, "Line1Feeder", areaId: 2);
var roots = InstanceTreeBuilder.Build([line1, line2], [other, hit], filter: "line1");
var root = Assert.Single(roots);
Assert.Equal("a:2", root.Key);
Assert.Equal("i:11", Assert.Single(root.Children).Key);
}
/// <summary>Verifies that the filter keeps matching instances with their ancestors and drops empty branches.</summary>
[Fact]
public void Build_Filter_KeepsMatchingInstancesWithAncestors_DropsEmptyBranches()
{
var line1 = MakeArea(1, "Line1");
var cellA = MakeArea(2, "Cell A", parentAreaId: 1);
var emptyArea = MakeArea(3, "Line2");
var p1 = MakeInstance(10, "P1", areaId: 2);
var zulu = MakeInstance(11, "Zulu");
var alpha = MakeInstance(12, "Alpha");
var roots = InstanceTreeBuilder.Build([line1, cellA, emptyArea], [p1, zulu, alpha], filter: "p1");
var root = Assert.Single(roots);
Assert.Equal("a:1", root.Key);
var cellNode = Assert.Single(root.Children);
Assert.Equal("a:2", cellNode.Key);
var leaf = Assert.Single(cellNode.Children);
Assert.Equal("i:10", leaf.Key);
}
/// <summary>Verifies that a whitespace-only filter is treated as no filter.</summary>
[Fact]
public void Build_Filter_WhitespaceMeansNoFilter()
{
var line1 = MakeArea(1, "Line1");
var p1 = MakeInstance(10, "P1", areaId: 1);
var zulu = MakeInstance(11, "Zulu");
var roots = InstanceTreeBuilder.Build([line1], [p1, zulu], filter: " ");
Assert.Equal(new[] { "a:1", "i:11" }, roots.Select(n => n.Key));
Assert.Single(roots[0].Children);
}
/// <summary>Verifies that null or empty inputs produce an empty tree.</summary>
[Fact]
public void Build_NullOrEmptyInputs_ReturnEmpty()
{
Assert.Empty(InstanceTreeBuilder.Build(null, null, filter: null));
Assert.Empty(InstanceTreeBuilder.Build([], [], filter: null));
Assert.Empty(InstanceTreeBuilder.Build(null, [], filter: "anything"));
var orphanInstances = InstanceTreeBuilder.Build(null, [MakeInstance(1, "Solo")], filter: null);
Assert.Equal("i:1", Assert.Single(orphanInstances).Key);
var areasOnly = InstanceTreeBuilder.Build([MakeArea(1, "Line1")], null, filter: null);
Assert.Equal("a:1", Assert.Single(areasOnly).Key);
}
/// <summary>Verifies that an area with no instances is still shown when no filter is applied.</summary>
[Fact]
public void Build_AreaWithNoInstancesAndNoFilter_IsStillShown()
{
var empty = MakeArea(1, "Empty");
var roots = InstanceTreeBuilder.Build([empty], [], filter: null);
var root = Assert.Single(roots);
Assert.Equal("a:1", root.Key);
Assert.False(root.HasChildren);
}
}