using NSubstitute; using ZB.MOM.WW.ScadaBridge.CentralUI.ScriptAnalysis; using ZB.MOM.WW.ScadaBridge.Commons.Types; namespace ZB.MOM.WW.ScadaBridge.CentralUI.Tests.ScriptAnalysis; /// /// Deferred-work #14 (full fidelity): the Test-Run sandbox routes value-equality /// WaitAsync/WaitForAsync to the bound instance via /// ; predicate overloads and unbound runs still /// throw a clearly-labelled . /// public class SandboxWaitForAttributeTests { private static SandboxAttributeAccessor BoundAccessor(ISandboxInstanceGateway gateway) => new(new SandboxInstanceContext(gateway), prefix: string.Empty); [Fact] public async Task WaitAsync_ValueForm_RoutesThroughGateway_AndReturnsMatched() { var gateway = Substitute.For(); gateway.WaitForAttributeAsync("Flag", Arg.Any(), Arg.Any(), false, Arg.Any()) .Returns(new WaitResult(true, true, "Good", false)); var accessor = BoundAccessor(gateway); var matched = await accessor.WaitAsync("Flag", true, TimeSpan.FromSeconds(5)); Assert.True(matched); // The target is codec-encoded and the resolved (root-scope) name is passed through. await gateway.Received(1).WaitForAttributeAsync( "Flag", AttributeValueCodec.Encode(true), TimeSpan.FromSeconds(5), false, Arg.Any()); } [Fact] public async Task WaitForAsync_ValueForm_PassesRequireGoodQuality_AndReturnsFullResult() { var gateway = Substitute.For(); gateway.WaitForAttributeAsync("Done", Arg.Any(), Arg.Any(), true, Arg.Any()) .Returns(new WaitResult(true, 7, "Good", false)); var accessor = BoundAccessor(gateway); var result = await accessor.WaitForAsync("Done", 7, TimeSpan.FromSeconds(3), requireGoodQuality: true); Assert.True(result.Matched); Assert.Equal(7, result.Value); Assert.Equal("Good", result.Quality); await gateway.Received(1).WaitForAttributeAsync( "Done", AttributeValueCodec.Encode(7), TimeSpan.FromSeconds(3), true, Arg.Any()); } [Fact] public async Task WaitAsync_PredicateForm_Throws() { var accessor = BoundAccessor(Substitute.For()); var ex = await Assert.ThrowsAsync( () => accessor.WaitAsync("Done", v => v != null, TimeSpan.FromSeconds(1))); Assert.Contains("predicate", ex.Message, StringComparison.OrdinalIgnoreCase); } [Fact] public async Task WaitForAsync_PredicateForm_Throws() { var accessor = BoundAccessor(Substitute.For()); await Assert.ThrowsAsync( () => accessor.WaitForAsync("Done", v => v != null, TimeSpan.FromSeconds(1))); } [Fact] public async Task WaitAsync_ValueForm_UnboundInstance_Throws() { // No gateway bound → the sandbox has no instance to route to. var accessor = new SandboxAttributeAccessor(new SandboxInstanceContext(), prefix: string.Empty); var ex = await Assert.ThrowsAsync( () => accessor.WaitAsync("Flag", true, TimeSpan.FromSeconds(1))); Assert.Contains("deployed instance", ex.Message, StringComparison.OrdinalIgnoreCase); } }