diff --git a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceVirtualTagTests.cs b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceVirtualTagTests.cs
index d7fafe1c..dfb2399e 100644
--- a/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceVirtualTagTests.cs
+++ b/tests/Server/ZB.MOM.WW.OtOpcUa.AdminUI.Tests/Uns/UnsTreeServiceVirtualTagTests.cs
@@ -163,6 +163,24 @@ public sealed class UnsTreeServiceVirtualTagTests
result.Error.ShouldBe("A virtual tag named 'computed' already exists on this equipment.");
}
+ /// Creating a virtual tag with no script chosen is blocked.
+ [Fact]
+ public async Task CreateVirtualTag_no_script_blocked()
+ {
+ var (service, dbName) = Fresh();
+ SeedEquipmentAndScript(dbName);
+
+ var input = Input("VTAG-1", "computed", scriptId: "", changeTriggered: true);
+ var result = await service.CreateVirtualTagAsync("EQ-1", input);
+
+ result.Ok.ShouldBeFalse();
+ result.Error.ShouldNotBeNull();
+ result.Error.ShouldContain("Pick a script");
+
+ using var db = UnsTreeTestDb.CreateNamed(dbName);
+ db.VirtualTags.Any(v => v.VirtualTagId == "VTAG-1").ShouldBeFalse();
+ }
+
// ----- UpdateVirtualTag -----
/// Updating a virtual tag changes its mutable fields and keeps EquipmentId.
@@ -211,6 +229,29 @@ public sealed class UnsTreeServiceVirtualTagTests
result.Error.ShouldBe("Row no longer exists.");
}
+ /// Renaming a virtual tag to a name already used by another tag on the same equipment is blocked.
+ [Fact]
+ public async Task UpdateVirtualTag_duplicate_name_on_equipment_blocked()
+ {
+ var (service, dbName) = Fresh();
+ SeedEquipmentAndScript(dbName);
+ await service.CreateVirtualTagAsync("EQ-1", Input("VTAG-A", "vt_a"));
+ await service.CreateVirtualTagAsync("EQ-1", Input("VTAG-B", "vt_b"));
+
+ byte[] rv;
+ using (var db = UnsTreeTestDb.CreateNamed(dbName))
+ {
+ rv = db.VirtualTags.Single(v => v.VirtualTagId == "VTAG-A").RowVersion;
+ }
+
+ var input = Input("VTAG-A", "vt_b"); // try to rename to the name already used by VTAG-B
+ var result = await service.UpdateVirtualTagAsync("VTAG-A", input, rv);
+
+ result.Ok.ShouldBeFalse();
+ result.Error.ShouldNotBeNull();
+ result.Error.ShouldContain("already exists on this equipment");
+ }
+
// ----- DeleteVirtualTag -----
/// Deleting a virtual tag removes the row.