using Microsoft.EntityFrameworkCore; using ScadaLink.Commons.Entities.Templates; using ScadaLink.ConfigurationDatabase; using ScadaLink.ConfigurationDatabase.Repositories; namespace ScadaLink.ConfigurationDatabase.Tests; public class TemplateEngineRepositoryTests : IDisposable { private readonly ScadaLinkDbContext _context; private readonly TemplateEngineRepository _repository; public TemplateEngineRepositoryTests() { var options = new DbContextOptionsBuilder() .UseSqlite("DataSource=:memory:") .Options; _context = new ScadaLinkDbContext(options); _context.Database.OpenConnection(); _context.Database.EnsureCreated(); _repository = new TemplateEngineRepository(_context); } public void Dispose() { _context.Database.CloseConnection(); _context.Dispose(); } [Fact] public async Task GetTemplateWithChildrenAsync_ReturnsTemplateWithAllMemberCollectionsPopulated() { // Arrange: a template with one attribute, one alarm, one script and one composition. var composed = new Template("ComposedTemplate"); _context.Templates.Add(composed); await _context.SaveChangesAsync(); var template = new Template("ParentTemplate"); template.Attributes.Add(new TemplateAttribute("Attr1")); template.Alarms.Add(new TemplateAlarm("Alarm1")); template.Scripts.Add(new TemplateScript("Script1", "return 1;")); template.Compositions.Add(new TemplateComposition("Slot1") { ComposedTemplateId = composed.Id }); _context.Templates.Add(template); await _context.SaveChangesAsync(); // Act var loaded = await _repository.GetTemplateWithChildrenAsync(template.Id); // Assert: the method must deliver the template's child members to the caller, // not silently drop them. Regression guard for ConfigurationDatabase-001. Assert.NotNull(loaded); Assert.Equal(template.Id, loaded!.Id); Assert.Single(loaded.Attributes); Assert.Equal("Attr1", loaded.Attributes.First().Name); Assert.Single(loaded.Alarms); Assert.Equal("Alarm1", loaded.Alarms.First().Name); Assert.Single(loaded.Scripts); Assert.Equal("Script1", loaded.Scripts.First().Name); Assert.Single(loaded.Compositions); Assert.Equal("Slot1", loaded.Compositions.First().InstanceName); } [Fact] public async Task GetTemplateWithChildrenAsync_ReturnsNull_WhenTemplateDoesNotExist() { var loaded = await _repository.GetTemplateWithChildrenAsync(9999); Assert.Null(loaded); } [Fact] public async Task GetTemplateWithChildrenAsync_PreservesParentTemplateId_ForInheritanceChainWalk() { // FlatteningPipeline.BuildTemplateChainAsync walks ParentTemplateId upward. // The result of GetTemplateWithChildrenAsync must carry that link intact. var baseTemplate = new Template("BaseTemplate"); _context.Templates.Add(baseTemplate); await _context.SaveChangesAsync(); var derived = new Template("DerivedTemplate") { ParentTemplateId = baseTemplate.Id }; _context.Templates.Add(derived); await _context.SaveChangesAsync(); var loaded = await _repository.GetTemplateWithChildrenAsync(derived.Id); Assert.NotNull(loaded); Assert.Equal(baseTemplate.Id, loaded!.ParentTemplateId); } }