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);
}
}