using Microsoft.Extensions.DependencyInjection; using ZB.MOM.WW.ScadaBridge.SiteEventLogging; namespace ZB.MOM.WW.ScadaBridge.SiteRuntime.Tests.TestSupport; /// /// WP3.1 parity pin 3: an that counts /// calls and each scope's /// , so a test can assert that one script run creates /// exactly one DI scope and disposes it exactly once — on the success, failure, AND timeout /// paths alike. Removing the per-run execution actor moved the scope's finally into /// ; a scope leaked /// there would silently leak every scoped service a script touches. /// public sealed class ScopeSpyServiceProvider(ISiteEventLogger? logger = null) : IServiceProvider, IServiceScopeFactory { private int _scopesCreated; private int _scopesDisposed; /// Scopes created so far. public int ScopesCreated => Volatile.Read(ref _scopesCreated); /// Scope disposals observed so far (double-disposal is counted twice, deliberately). public int ScopesDisposed => Volatile.Read(ref _scopesDisposed); /// public object? GetService(Type serviceType) { if (serviceType == typeof(ISiteEventLogger)) return logger; if (serviceType == typeof(IServiceScopeFactory)) return this; return null; } /// public IServiceScope CreateScope() { Interlocked.Increment(ref _scopesCreated); return new SpyScope(this); } private sealed class SpyScope(ScopeSpyServiceProvider owner) : IServiceScope { public IServiceProvider ServiceProvider => owner; public void Dispose() => Interlocked.Increment(ref owner._scopesDisposed); } }