feat(adminui): create-new-script from the inline virtual-tag panel

This commit is contained in:
Joseph Doherty
2026-06-16 16:44:14 -04:00
parent 526eebb3bb
commit c98625fd9f
4 changed files with 192 additions and 1 deletions
@@ -0,0 +1,86 @@
using System.Security.Cryptography;
using System.Text;
using Microsoft.EntityFrameworkCore;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;
/// <summary>
/// Verifies <see cref="UnsTreeService.CreateScriptAsync"/> — the create-new-script path the inline
/// virtual-tag panel calls when no script is bound yet. A new <c>Script</c> row is inserted with a
/// system-generated <c>SC-…</c> id (mirroring the Script-edit page convention), a blank source, a
/// hash matching that blank source, and the <c>CSharp</c> language; the new id is returned via
/// <see cref="UnsMutationResult.CreatedId"/> so the panel can bind the virtual tag to it. Two calls
/// produce two distinct rows with distinct ids.
/// </summary>
[Trait("Category", "Unit")]
public sealed class UnsTreeServiceCreateScriptTests
{
private static (UnsTreeService Service, string DbName) Fresh()
{
var dbName = $"uns-createscript-{Guid.NewGuid():N}";
return (new UnsTreeService(UnsTreeTestDb.Factory(dbName)), dbName);
}
private static string HashOf(string source) =>
Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(source)));
/// <summary>
/// A create inserts exactly one Script row carrying a non-empty generated id, the expected blank
/// source + matching hash, the CSharp language, and a name; the generated id is echoed back.
/// </summary>
[Fact]
public async Task CreateScript_inserts_one_row_with_generated_id_and_blank_source()
{
var (service, dbName) = Fresh();
var result = await service.CreateScriptAsync("my new script");
result.Ok.ShouldBeTrue();
result.Error.ShouldBeNull();
result.CreatedId.ShouldNotBeNullOrWhiteSpace();
result.CreatedId!.ShouldStartWith("SC-");
using var db = UnsTreeTestDb.CreateNamed(dbName);
db.Scripts.Count().ShouldBe(1);
var script = db.Scripts.Single();
script.ScriptId.ShouldBe(result.CreatedId);
script.Name.ShouldBe("my new script");
script.SourceCode.ShouldBe("");
script.SourceHash.ShouldBe(HashOf(""));
script.Language.ShouldBe("CSharp");
}
/// <summary>A whitespace/empty name falls back to a sensible non-empty default.</summary>
[Fact]
public async Task CreateScript_blank_name_uses_a_default_name()
{
var (service, dbName) = Fresh();
var result = await service.CreateScriptAsync(" ");
result.Ok.ShouldBeTrue();
using var db = UnsTreeTestDb.CreateNamed(dbName);
db.Scripts.Single().Name.ShouldNotBeNullOrWhiteSpace();
}
/// <summary>Two creates insert two rows with distinct, non-empty ids.</summary>
[Fact]
public async Task CreateScript_twice_produces_distinct_ids()
{
var (service, dbName) = Fresh();
var first = await service.CreateScriptAsync("first");
var second = await service.CreateScriptAsync("second");
first.Ok.ShouldBeTrue();
second.Ok.ShouldBeTrue();
first.CreatedId.ShouldNotBe(second.CreatedId);
using var db = UnsTreeTestDb.CreateNamed(dbName);
db.Scripts.Count().ShouldBe(2);
db.Scripts.Select(s => s.ScriptId).Distinct().Count().ShouldBe(2);
}
}