test(adminui): DB-backed tests for ScriptTagCatalog.GetEquipmentRelativeLeavesAsync

This commit is contained in:
Joseph Doherty
2026-06-10 08:12:52 -04:00
parent a7c1d7f7cb
commit 6c23a6763a
@@ -287,4 +287,85 @@ public sealed class ScriptTagCatalogTests
(await catalog.GetTagInfoAsync("motor.speed", default)).ShouldBeNull();
(await catalog.GetTagInfoAsync("Motor.Speed", default)).ShouldNotBeNull();
}
// -----------------------------------------------------------------------
// GetEquipmentRelativeLeavesAsync — DB-backed tests
// -----------------------------------------------------------------------
// Seeded paths and their leaf derivation:
// TAG-EQ → "Motor.Speed" → leaf "Speed"
// TAG-SP → "DelmiaReceiver_001.DownloadPath" → leaf "DownloadPath"
// VTAG-1 → "Computed" → NO dot → excluded
// -----------------------------------------------------------------------
/// <summary>A null filter returns one leaf per dot-bearing path; the no-dot virtual-tag path is excluded.</summary>
[Fact]
public async Task GetEquipmentRelativeLeaves_no_filter_returns_dot_bearing_leaves_only()
{
var (catalog, opts) = Fresh();
Seed(opts);
var leaves = await catalog.GetEquipmentRelativeLeavesAsync(null, default);
// Leaves derived from the two dot-bearing paths in Seed().
leaves.ShouldContain("Speed"); // from "Motor.Speed"
leaves.ShouldContain("DownloadPath"); // from "DelmiaReceiver_001.DownloadPath"
// Virtual tag "Computed" has no dot — must be excluded.
leaves.ShouldNotContain("Computed");
}
/// <summary>A prefix filter narrows to leaves that start with the given string (e.g. "Sp" → "Speed", not "DownloadPath").</summary>
[Fact]
public async Task GetEquipmentRelativeLeaves_prefix_filter_narrows_to_matching_leaves()
{
var (catalog, opts) = Fresh();
Seed(opts);
var leaves = await catalog.GetEquipmentRelativeLeavesAsync("Sp", default);
leaves.ShouldContain("Speed");
leaves.ShouldNotContain("DownloadPath");
leaves.ShouldAllBe(l => l.StartsWith("Sp", StringComparison.OrdinalIgnoreCase));
}
/// <summary>The prefix filter is case-insensitive: "sp" (lowercase) still matches the leaf "Speed".</summary>
[Fact]
public async Task GetEquipmentRelativeLeaves_prefix_filter_is_case_insensitive()
{
var (catalog, opts) = Fresh();
Seed(opts);
var leaves = await catalog.GetEquipmentRelativeLeavesAsync("sp", default);
leaves.ShouldContain("Speed");
}
/// <summary>Two paths sharing the same leaf after different object prefixes produce one distinct entry.</summary>
[Fact]
public async Task GetEquipmentRelativeLeaves_duplicate_leaves_are_deduplicated()
{
var (catalog, opts) = Fresh();
Seed(opts);
// Add a second equipment tag whose FullName produces the same leaf "Speed" as TAG-EQ.
using (var db = new OtOpcUaConfigDbContext(opts))
{
db.Tags.Add(new Tag
{
TagId = "TAG-EQ2",
DriverInstanceId = "DRV-1",
EquipmentId = "EQ-1",
Name = "Speed2",
DataType = "Float",
AccessLevel = TagAccessLevel.Read,
TagConfig = "{\"FullName\":\"Conveyor.Speed\"}",
});
db.SaveChanges();
}
var leaves = await catalog.GetEquipmentRelativeLeavesAsync(null, default);
// "Speed" must appear exactly once despite being produced by two different paths.
leaves.Count(l => string.Equals(l, "Speed", StringComparison.Ordinal)).ShouldBe(1);
}
}