using ZB.MOM.WW.ScadaBridge.ScriptAnalysis; namespace ZB.MOM.WW.ScadaBridge.ScriptAnalysis.Tests; /// /// Review 2026-10-21 04/P3: /// is memoised by code hash for the default (policy) reference set, so the bundle /// importer's preview and apply passes — which call it with no change at their call /// sites — do not redo a full-framework semantic analysis per script. A cache hit /// returns the very same verdict instance, which is what these tests observe. /// public class ScriptTrustValidatorCacheTests { /// Verifies that the same violating code analysed twice is served from the cache. [Fact] public void FindViolations_SameCodeTwice_SecondCallIsCacheHit() { var code = $"var x = System.IO.File.Exists(\"{Guid.NewGuid()}\");"; var first = ScriptTrustValidator.FindViolations(code); var second = ScriptTrustValidator.FindViolations(code); Assert.NotEmpty(second); Assert.Same(first, second); // pre-fix: a fresh list per call } /// Verifies that a clean verdict is cached too. [Fact] public void FindViolations_CleanCodeTwice_SecondCallIsCacheHit() { var code = $"var x = \"{Guid.NewGuid()}\".Length;"; var first = ScriptTrustValidator.FindViolations(code); var second = ScriptTrustValidator.FindViolations(code); Assert.Empty(second); Assert.Same(first, second); } /// /// Verifies that a call with extra references is never served from (or stored in) /// the cache — extra references can change symbol resolution, so the verdict is a /// pure function of the code only for the default reference set. /// [Fact] public void FindViolations_WithExtraReferences_BypassesCache() { var code = $"var x = System.IO.File.Exists(\"{Guid.NewGuid()}\");"; var extra = new[] { Microsoft.CodeAnalysis.MetadataReference.CreateFromFile(typeof(ScriptCompileSurface).Assembly.Location) }; var a = ScriptTrustValidator.FindViolations(code, extra); var b = ScriptTrustValidator.FindViolations(code, extra); var cached = ScriptTrustValidator.FindViolations(code); Assert.NotSame(a, b); Assert.NotSame(a, cached); Assert.NotSame(b, cached); } /// Verifies that the shared verdict cannot be mutated by a caller to poison the cache. [Fact] public void FindViolations_ReturnedList_IsReadOnly() { var code = $"var x = System.IO.File.Exists(\"{Guid.NewGuid()}\");"; var verdict = ScriptTrustValidator.FindViolations(code); Assert.False(verdict is List); Assert.True(verdict is System.Collections.Generic.ICollection { IsReadOnly: true }); } }