using System.Security.Claims; using Bunit; using Microsoft.AspNetCore.Components.Authorization; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.DependencyInjection; using NSubstitute; using ZB.MOM.WW.ScadaBridge.CentralUI.ScriptAnalysis; using ZB.MOM.WW.ScadaBridge.CentralUI.Services; using ZB.MOM.WW.ScadaBridge.CentralUI.Components.Shared; using ZB.MOM.WW.ScadaBridge.Commons.Entities.Instances; using ZB.MOM.WW.ScadaBridge.Commons.Entities.Sites; using ZB.MOM.WW.ScadaBridge.Commons.Entities.Templates; using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories; using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Services; using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management; using ZB.MOM.WW.ScadaBridge.Security; using ZB.MOM.WW.ScadaBridge.TemplateEngine; using TemplateEditPage = ZB.MOM.WW.ScadaBridge.CentralUI.Components.Pages.Design.TemplateEdit; namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.Design; /// /// bUnit tests for the template editor's READ-ONLY inheritance preview (M9-T26b): /// rendering the FULL transitively-resolved inherited member set (not just the /// immediate base) annotated with origin, plus a read-only base-changed staleness /// banner. The resolve query is dispatched through /// , which is substituted here so the /// tests feed a crafted without a real /// ManagementActor. No mutation / deploy-path behavior is exercised. /// public class TemplateEditInheritedSetTests : BunitContext { private readonly ITemplateEngineRepository _repo = Substitute.For(); private readonly ICentralUiRepository _centralUi = Substitute.For(); private readonly IAuditService _audit = Substitute.For(); private readonly ISharedScriptCatalog _sharedScripts = Substitute.For(); private readonly ITemplateInheritanceQueryService _resolve = Substitute.For(); // The derived template under edit (id 30) and its immediate base (id 20). private const int DerivedId = 30; private const int BaseId = 20; public TemplateEditInheritedSetTests() { Services.AddSingleton(_repo); Services.AddSingleton(_centralUi); Services.AddSingleton(_audit); Services.AddSingleton(_resolve); Services.AddScoped(); Services.AddScoped(); // ScriptAnalysisService is injected but never exercised on the initial // render — supply its collaborators so DI can construct it. Services.AddSingleton(_sharedScripts); Services.AddSingleton(new MemoryCache(new MemoryCacheOptions())); Services.AddScoped(); AddTestAuth(); SeedDerivedTemplateRows(); } private void AddTestAuth() { var claims = new[] { new Claim(JwtTokenService.UsernameClaimType, "tester"), new Claim(JwtTokenService.RoleClaimType, "Designer"), }; var user = new ClaimsPrincipal(new ClaimsIdentity(claims, "TestAuth")); Services.AddSingleton(new TestAuthStateProvider(user)); Services.AddAuthorizationCore(); } /// /// Seeds the stored-row repository view of a derived template. The stored rows /// deliberately omit the transitively-inherited members — those only appear via /// the resolved set the query service returns. /// private void SeedDerivedTemplateRows() { var grandparent = new Template("Root") { Id = 10 }; var baseTemplate = new Template("Base") { Id = BaseId, ParentTemplateId = 10 }; var derived = new Template("Derived") { Id = DerivedId, ParentTemplateId = BaseId, IsDerived = true, }; _repo.GetAllTemplatesAsync(Arg.Any()) .Returns(Task.FromResult>( new List