Files
Joseph Doherty faef2d0de6 Phase 2 WP-1–13+23: Template Engine CRUD, composition, overrides, locking, collision detection, acyclicity
- WP-23: ITemplateEngineRepository full EF Core implementation
- WP-1: Template CRUD with deletion constraints (instances, children, compositions)
- WP-2–4: Attribute, alarm, script definitions with lock flags and override granularity
- WP-5: Shared script CRUD with syntax validation
- WP-6–7: Composition with recursive nesting and canonical naming
- WP-8–11: Override granularity, locking rules, inheritance/composition scope
- WP-12: Naming collision detection on canonical names (recursive)
- WP-13: Graph acyclicity (inheritance + composition cycles)
Core services: TemplateService, SharedScriptService, TemplateResolver,
LockEnforcer, CollisionDetector, CycleDetector. 358 tests pass.
2026-03-16 20:10:34 -04:00

75 lines
2.3 KiB
C#

using ScadaLink.TemplateEngine.Validation;
namespace ScadaLink.TemplateEngine.Tests.Validation;
public class ScriptCompilerTests
{
private readonly ScriptCompiler _sut = new();
[Fact]
public void TryCompile_ValidCode_ReturnsSuccess()
{
var result = _sut.TryCompile("var x = 1; if (x > 0) { x++; }", "Test");
Assert.True(result.IsSuccess);
}
[Fact]
public void TryCompile_EmptyCode_ReturnsFailure()
{
var result = _sut.TryCompile("", "Test");
Assert.True(result.IsFailure);
Assert.Contains("empty", result.Error, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void TryCompile_MismatchedBraces_ReturnsFailure()
{
var result = _sut.TryCompile("if (true) { x = 1;", "Test");
Assert.True(result.IsFailure);
Assert.Contains("braces", result.Error, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void TryCompile_UnclosedBlockComment_ReturnsFailure()
{
var result = _sut.TryCompile("/* this is never closed", "Test");
Assert.True(result.IsFailure);
Assert.Contains("comment", result.Error, StringComparison.OrdinalIgnoreCase);
}
[Theory]
[InlineData("System.IO.File.ReadAllText(\"x\");")]
[InlineData("System.Diagnostics.Process.Start(\"cmd\");")]
[InlineData("System.Threading.Thread.Sleep(1000);")]
[InlineData("System.Reflection.Assembly.Load(\"x\");")]
[InlineData("System.Net.Sockets.TcpClient c;")]
[InlineData("System.Net.Http.HttpClient c;")]
public void TryCompile_ForbiddenApi_ReturnsFailure(string code)
{
var result = _sut.TryCompile(code, "Test");
Assert.True(result.IsFailure);
Assert.Contains("forbidden", result.Error, StringComparison.OrdinalIgnoreCase);
}
[Fact]
public void TryCompile_BracesInStrings_Ignored()
{
var result = _sut.TryCompile("var s = \"{ not a brace }\";", "Test");
Assert.True(result.IsSuccess);
}
[Fact]
public void TryCompile_BracesInComments_Ignored()
{
var result = _sut.TryCompile("// { not a brace\nvar x = 1;", "Test");
Assert.True(result.IsSuccess);
}
[Fact]
public void TryCompile_BlockCommentWithBraces_Ignored()
{
var result = _sut.TryCompile("/* { } */ var x = 1;", "Test");
Assert.True(result.IsSuccess);
}
}