using Microsoft.CodeAnalysis.CSharp.Scripting; using Microsoft.CodeAnalysis.Scripting; using ZB.MOM.WW.ScadaBridge.SiteRuntime.Scripts; namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests.Scripts; /// /// Tests for the process-wide . The cache is /// static/process-wide state, so this class shares the "SiteScriptCompileCache" xunit /// collection with ScriptCompilationServiceTests (no cross-class parallelism) and /// calls at the top of each test. /// [Collection("SiteScriptCompileCache")] public class SiteScriptCompileCacheTests { private static ScriptCompilationResult Ok() => ScriptCompilationResult.Succeeded(CSharpScript.Create("1", ScriptOptions.Default, typeof(ScriptGlobals))); [Fact] public void GetOrAdd_SameCodeAndGlobals_ComputesOnce() { SiteScriptCompileCache.Clear(); var factoryCalls = 0; ScriptCompilationResult Factory() { factoryCalls++; return Ok(); } var r1 = SiteScriptCompileCache.GetOrAdd("return 1;", typeof(ScriptGlobals), Factory); var r2 = SiteScriptCompileCache.GetOrAdd("return 1;", typeof(ScriptGlobals), Factory); Assert.Equal(1, factoryCalls); Assert.Same(r1, r2); Assert.Equal(1, SiteScriptCompileCache.Hits); } [Fact] public void GetOrAdd_SameCode_DifferentGlobals_AreSeparateEntries() { SiteScriptCompileCache.Clear(); SiteScriptCompileCache.GetOrAdd("1 > 0", typeof(ScriptGlobals), Ok); SiteScriptCompileCache.GetOrAdd("1 > 0", typeof(TriggerExpressionGlobals), Ok); Assert.Equal(2, SiteScriptCompileCache.Count); Assert.Equal(0, SiteScriptCompileCache.Hits); // no cross-globals hit } [Fact] public void Overflow_ClearsWholesale() { SiteScriptCompileCache.Clear(); for (var i = 0; i <= SiteScriptCompileCache.MaxEntries; i++) SiteScriptCompileCache.GetOrAdd($"return {i};", typeof(ScriptGlobals), Ok); Assert.True(SiteScriptCompileCache.Count <= SiteScriptCompileCache.MaxEntries); } }