using Moq; using ScadaLink.Commons.Entities.Scripts; using ScadaLink.Commons.Interfaces.Repositories; using ScadaLink.Commons.Interfaces.Services; namespace ScadaLink.TemplateEngine.Tests; public class SharedScriptServiceTests { private readonly Mock _repoMock; private readonly Mock _auditMock; private readonly SharedScriptService _service; public SharedScriptServiceTests() { _repoMock = new Mock(); _auditMock = new Mock(); _repoMock.Setup(r => r.SaveChangesAsync(It.IsAny())).ReturnsAsync(1); _service = new SharedScriptService(_repoMock.Object, _auditMock.Object); } [Fact] public async Task CreateSharedScript_Success() { _repoMock.Setup(r => r.GetSharedScriptByNameAsync("Helpers", It.IsAny())) .ReturnsAsync((SharedScript?)null); var result = await _service.CreateSharedScriptAsync( "Helpers", "public static int Add(int a, int b) { return a + b; }", null, null, "admin"); Assert.True(result.IsSuccess); Assert.Equal("Helpers", result.Value.Name); _repoMock.Verify(r => r.AddSharedScriptAsync(It.IsAny(), It.IsAny()), Times.Once); } [Fact] public async Task CreateSharedScript_EmptyName_Fails() { var result = await _service.CreateSharedScriptAsync("", "code", null, null, "admin"); Assert.True(result.IsFailure); Assert.Contains("name is required", result.Error); } [Fact] public async Task CreateSharedScript_EmptyCode_Fails() { var result = await _service.CreateSharedScriptAsync("Test", "", null, null, "admin"); Assert.True(result.IsFailure); Assert.Contains("code is required", result.Error); } [Fact] public async Task CreateSharedScript_DuplicateName_Fails() { _repoMock.Setup(r => r.GetSharedScriptByNameAsync("Helpers", It.IsAny())) .ReturnsAsync(new SharedScript("Helpers", "existing code")); var result = await _service.CreateSharedScriptAsync("Helpers", "new code", null, null, "admin"); Assert.True(result.IsFailure); Assert.Contains("already exists", result.Error); } [Fact] public async Task CreateSharedScript_UnbalancedBraces_Fails() { _repoMock.Setup(r => r.GetSharedScriptByNameAsync("Bad", It.IsAny())) .ReturnsAsync((SharedScript?)null); var result = await _service.CreateSharedScriptAsync("Bad", "public void Run() {", null, null, "admin"); Assert.True(result.IsFailure); Assert.Contains("Syntax error", result.Error); } [Fact] public async Task UpdateSharedScript_Success() { var existing = new SharedScript("Helpers", "old code") { Id = 1 }; _repoMock.Setup(r => r.GetSharedScriptByIdAsync(1, It.IsAny())).ReturnsAsync(existing); var result = await _service.UpdateSharedScriptAsync(1, "return 42;", null, null, "admin"); Assert.True(result.IsSuccess); Assert.Equal("return 42;", result.Value.Code); } [Fact] public async Task UpdateSharedScript_NotFound_Fails() { _repoMock.Setup(r => r.GetSharedScriptByIdAsync(999, It.IsAny())).ReturnsAsync((SharedScript?)null); var result = await _service.UpdateSharedScriptAsync(999, "code", null, null, "admin"); Assert.True(result.IsFailure); Assert.Contains("not found", result.Error); } [Fact] public async Task DeleteSharedScript_Success() { var existing = new SharedScript("Helpers", "code") { Id = 1 }; _repoMock.Setup(r => r.GetSharedScriptByIdAsync(1, It.IsAny())).ReturnsAsync(existing); var result = await _service.DeleteSharedScriptAsync(1, "admin"); Assert.True(result.IsSuccess); _repoMock.Verify(r => r.DeleteSharedScriptAsync(1, It.IsAny()), Times.Once); } [Fact] public async Task DeleteSharedScript_NotFound_Fails() { _repoMock.Setup(r => r.GetSharedScriptByIdAsync(999, It.IsAny())).ReturnsAsync((SharedScript?)null); var result = await _service.DeleteSharedScriptAsync(999, "admin"); Assert.True(result.IsFailure); Assert.Contains("not found", result.Error); } // Syntax validation unit tests [Theory] [InlineData("return 42;", null)] [InlineData("public void Run() { }", null)] [InlineData("var x = new int[] { 1, 2, 3 };", null)] [InlineData("if (a > b) { return a; } else { return b; }", null)] public void ValidateSyntax_ValidCode_ReturnsNull(string code, string? expected) { Assert.Equal(expected, SharedScriptService.ValidateSyntax(code)); } [Theory] [InlineData("public void Run() {")] [InlineData("return a + b);")] [InlineData("var x = new int[] { 1, 2 ;")] public void ValidateSyntax_InvalidCode_ReturnsError(string code) { var result = SharedScriptService.ValidateSyntax(code); Assert.NotNull(result); Assert.Contains("Syntax error", result); } }