using Microsoft.AspNetCore.Components;
using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Raw;
///
/// R04 H2: the modals' DynamicComponent parameter dictionaries are reused across renders while their
/// values are unchanged, and rebuilt — carrying the current value — the moment one changes. The second
/// half is the regression a naive build-once cache would introduce (stale JSON stranding every edit).
///
[Trait("Category", "Unit")]
public sealed class ParameterDictionaryCacheTests
{
[Fact]
public void Unchanged_values_return_the_same_dictionary()
{
var cache = new ParameterDictionaryCache();
var builds = 0;
var json = "{}";
Dictionary Build() { builds++; return new() { ["Json"] = json }; }
var first = cache.Get([json], Build);
cache.Get([json], Build).ShouldBeSameAs(first);
builds.ShouldBe(1);
}
[Fact]
public void A_changed_value_rebuilds_with_the_current_value()
{
var cache = new ParameterDictionaryCache();
var json = "{}";
Dictionary Build() => new() { ["Json"] = json };
cache.Get([json], Build)["Json"].ShouldBe("{}");
json = "{\"a\":1}";
cache.Get([json], Build)["Json"].ShouldBe("{\"a\":1}");
}
[Fact]
public void Null_values_compare_and_reset_forces_a_rebuild()
{
var cache = new ParameterDictionaryCache();
var builds = 0;
Dictionary Build() { builds++; return new(); }
cache.Get(["x", null], Build);
cache.Get(["x", null], Build);
builds.ShouldBe(1);
cache.Reset();
cache.Get(["x", null], Build);
builds.ShouldBe(2);
}
[Fact]
public void Modals_build_their_parameters_through_the_cache_with_reused_callbacks()
{
foreach (var (path, cacheField) in new[]
{
(new[] { "Components", "Shared", "Drivers", "DriverConfigModal.razor" }, "_formParameterCache.Get("),
(new[] { "Components", "Shared", "Drivers", "DeviceModal.razor" }, "_deviceFormParameterCache.Get("),
(new[] { "Components", "Shared", "Raw", "RawTagModal.razor" }, "_editorParameterCache.Get("),
})
{
var src = AdminUiSource.Read(path);
src.ShouldContain(cacheField, customMessage: path[^1]);
// Every EventCallback is created behind a ??= so it is made once per component.
var all = System.Text.RegularExpressions.Regex.Matches(src, @"EventCallback\.Factory\.Create").Count;
var once = System.Text.RegularExpressions.Regex.Matches(src, @"\?\?=\s*EventCallback\.Factory\.Create").Count;
all.ShouldBeGreaterThan(0, path[^1]);
once.ShouldBe(all, path[^1]);
}
}
[Fact]
public void RawTagModal_reuses_its_callback_across_renders()
{
var modal = new ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Raw.RawTagModal();
var first = modal.BuildEditorParameters();
var second = modal.BuildEditorParameters();
second.ShouldBeSameAs(first);
((EventCallback)first["ConfigJsonChanged"]).HasDelegate.ShouldBeTrue();
}
}