feat(vtag): passthrough fast-path skips Roslyn for mirror scripts (A)

This commit is contained in:
Joseph Doherty
2026-06-07 15:26:20 -04:00
parent 3834400f05
commit 08d7477860
5 changed files with 256 additions and 3 deletions
@@ -1,3 +1,5 @@
using System.Collections;
using System.Reflection;
using Microsoft.Extensions.Logging.Abstractions;
using Shouldly;
using Xunit;
@@ -95,4 +97,135 @@ public sealed class RoslynVirtualTagEvaluatorTests
result.Success.ShouldBeFalse();
result.Reason!.ShouldContain("disposed");
}
// ── A — passthrough fast-path: the mirror shape `return ctx.GetTag("X").Value;`
// is answered directly from the dependency value, skipping Roslyn compilation. ──
/// <summary>Mirror passthrough returns the dependency value verbatim without compiling.</summary>
[Fact]
public void Passthrough_returns_dependency_value_without_compiling()
{
using var sut = new RoslynVirtualTagEvaluator(NullLogger<RoslynVirtualTagEvaluator>.Instance);
var result = sut.Evaluate(
virtualTagId: "vt-mirror",
expression: "return ctx.GetTag(\"a\").Value;",
dependencies: new Dictionary<string, object?> { ["a"] = 42 });
result.Success.ShouldBeTrue(result.Reason);
result.Value.ShouldBe(42);
}
/// <summary>The passthrough fast-path returns the raw object reference, not a re-boxed copy —
/// proof the value flowed straight through without round-tripping a Roslyn script run.</summary>
[Fact]
public void Passthrough_returns_same_object_reference_as_dependency()
{
using var sut = new RoslynVirtualTagEvaluator(NullLogger<RoslynVirtualTagEvaluator>.Instance);
var payload = new object();
var result = sut.Evaluate(
virtualTagId: "vt-ref",
expression: "return ctx.GetTag(\"a\").Value;",
dependencies: new Dictionary<string, object?> { ["a"] = payload });
result.Success.ShouldBeTrue(result.Reason);
result.Value.ShouldBeSameAs(payload);
}
/// <summary>Whitespace-tolerant mirror shapes still take the passthrough fast-path.</summary>
[Fact]
public void Passthrough_whitespace_variants_match()
{
using var sut = new RoslynVirtualTagEvaluator(NullLogger<RoslynVirtualTagEvaluator>.Instance);
var result = sut.Evaluate(
virtualTagId: "vt-ws",
expression: " return ctx . GetTag( \"a\" ) . Value ; ",
dependencies: new Dictionary<string, object?> { ["a"] = 7 });
result.Success.ShouldBeTrue(result.Reason);
result.Value.ShouldBe(7);
}
/// <summary>A near-miss (arithmetic on the mirror value) falls through to Roslyn and still works.</summary>
[Fact]
public void Non_passthrough_falls_through_to_Roslyn()
{
using var sut = new RoslynVirtualTagEvaluator(NullLogger<RoslynVirtualTagEvaluator>.Instance);
var result = sut.Evaluate(
virtualTagId: "vt-plus1",
expression: "return (int)ctx.GetTag(\"a\").Value + 1;",
dependencies: new Dictionary<string, object?> { ["a"] = 42 });
result.Success.ShouldBeTrue(result.Reason);
result.Value.ShouldBe(43);
}
/// <summary>Passthrough with an absent dependency yields the SAME result the Roslyn path
/// produces: <c>GetTag</c> returns a Bad snapshot whose <c>.Value</c> is null, so the script
/// returns null and the evaluator wraps it as <c>Ok(null)</c> (success, null value).</summary>
[Fact]
public void Passthrough_missing_dependency_matches_Roslyn_behaviour()
{
using var sut = new RoslynVirtualTagEvaluator(NullLogger<RoslynVirtualTagEvaluator>.Instance);
const string mirror = "return ctx.GetTag(\"missing\").Value;";
// Roslyn baseline: same source, but force a near-miss that compiles, to capture the
// not-found semantics independently. Here we just assert the mirror's own missing-dep
// result equals the documented Ok(null) shape.
var passthrough = sut.Evaluate("vt-miss", mirror, new Dictionary<string, object?>());
passthrough.Success.ShouldBeTrue(passthrough.Reason);
passthrough.Value.ShouldBeNull();
passthrough.Reason.ShouldBeNull();
}
/// <summary>Cross-check: the equivalent Roslyn-compiled read of a missing dependency
/// produces exactly the same <c>Ok(null)</c> result, proving the fast-path is byte-identical.</summary>
[Fact]
public void Roslyn_missing_dependency_also_returns_Ok_null()
{
using var sut = new RoslynVirtualTagEvaluator(NullLogger<RoslynVirtualTagEvaluator>.Instance);
// `(object?)...Value` forces the compiled path (not the mirror shape) but reads the same
// missing tag; result must match the passthrough missing-dep result above.
var result = sut.Evaluate(
"vt-miss-roslyn",
"return (object?)ctx.GetTag(\"missing\").Value;",
new Dictionary<string, object?>());
result.Success.ShouldBeTrue(result.Reason);
result.Value.ShouldBeNull();
result.Reason.ShouldBeNull();
}
/// <summary>Decisive proof the fast-path skips Roslyn: the compiled-script cache (which every
/// Roslyn evaluation populates via <c>GetOrAdd</c>) stays EMPTY after a mirror evaluation, then
/// grows to one entry once a genuine (non-mirror) expression forces compilation.</summary>
[Fact]
public void Passthrough_does_not_populate_the_compiled_script_cache()
{
using var sut = new RoslynVirtualTagEvaluator(NullLogger<RoslynVirtualTagEvaluator>.Instance);
// Mirror shape — must take the fast-path, leaving the Roslyn cache untouched.
sut.Evaluate("vt-mirror", "return ctx.GetTag(\"a\").Value;",
new Dictionary<string, object?> { ["a"] = 1 });
CompiledCacheCount(sut).ShouldBe(0);
// Non-mirror shape — must compile, populating exactly one cache entry.
sut.Evaluate("vt-real", "return (int)ctx.GetTag(\"a\").Value + 1;",
new Dictionary<string, object?> { ["a"] = 1 });
CompiledCacheCount(sut).ShouldBe(1);
}
/// <summary>Reads the count of the private compiled-script cache via reflection.</summary>
private static int CompiledCacheCount(RoslynVirtualTagEvaluator sut)
{
var field = typeof(RoslynVirtualTagEvaluator)
.GetField("_cache", BindingFlags.Instance | BindingFlags.NonPublic);
field.ShouldNotBeNull();
var cache = (ICollection)field.GetValue(sut)!;
return cache.Count;
}
}