feat(vtag): passthrough fast-path skips Roslyn for mirror scripts (A)
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.Core.Scripting;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.Core.Scripting.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Unit tests for <see cref="PassthroughScript"/> — the Roslyn-free classifier that recognises
|
||||
/// the trivial mirror shape <c>return ctx.GetTag("X").Value;</c>. The pattern must be narrow:
|
||||
/// any near-miss (arithmetic, a different member, multi-statement, a different method) falls
|
||||
/// through so the Roslyn path stays authoritative.
|
||||
/// </summary>
|
||||
public sealed class PassthroughScriptTests
|
||||
{
|
||||
/// <summary>The canonical mirror shape matches and captures the referenced tag.</summary>
|
||||
[Fact]
|
||||
public void Matches_canonical_mirror_and_captures_tag()
|
||||
{
|
||||
PassthroughScript.TryMatch("return ctx.GetTag(\"a\").Value;", out var tag).ShouldBeTrue();
|
||||
tag.ShouldBe("a");
|
||||
}
|
||||
|
||||
/// <summary>A dotted / hierarchical tag reference is captured verbatim.</summary>
|
||||
[Fact]
|
||||
public void Captures_dotted_tag_reference()
|
||||
{
|
||||
PassthroughScript.TryMatch("return ctx.GetTag(\"Area1.Machine.Speed\").Value;", out var tag)
|
||||
.ShouldBeTrue();
|
||||
tag.ShouldBe("Area1.Machine.Speed");
|
||||
}
|
||||
|
||||
/// <summary>Whitespace around every token is tolerated.</summary>
|
||||
[Fact]
|
||||
public void Tolerates_surrounding_and_inner_whitespace()
|
||||
{
|
||||
PassthroughScript.TryMatch(" return ctx . GetTag( \"a\" ) . Value ; ", out var tag)
|
||||
.ShouldBeTrue();
|
||||
tag.ShouldBe("a");
|
||||
}
|
||||
|
||||
/// <summary>Arithmetic on the mirror value is NOT a passthrough.</summary>
|
||||
[Fact]
|
||||
public void Rejects_arithmetic_on_value()
|
||||
{
|
||||
PassthroughScript.TryMatch("return (int)ctx.GetTag(\"a\").Value + 1;", out _).ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>Reading a different member (StatusCode) is NOT a passthrough.</summary>
|
||||
[Fact]
|
||||
public void Rejects_other_member_access()
|
||||
{
|
||||
PassthroughScript.TryMatch("return ctx.GetTag(\"a\").StatusCode;", out _).ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>A multi-statement body is NOT a passthrough.</summary>
|
||||
[Fact]
|
||||
public void Rejects_multi_statement_body()
|
||||
{
|
||||
PassthroughScript.TryMatch("var x = ctx.GetTag(\"a\").Value; return x;", out _).ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>A different method name is NOT a passthrough.</summary>
|
||||
[Fact]
|
||||
public void Rejects_different_method()
|
||||
{
|
||||
PassthroughScript.TryMatch("return ctx.GetVirtualTag(\"a\").Value;", out _).ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>Null / empty / whitespace input is rejected.</summary>
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData(" ")]
|
||||
public void Rejects_null_or_blank(string? source)
|
||||
{
|
||||
PassthroughScript.TryMatch(source, out var tag).ShouldBeFalse();
|
||||
tag.ShouldBe(string.Empty);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user