using Shouldly;
using Xunit;
namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests;
///
/// Gitea #516 — FOCAS was excluded from the first pass because it derives MORE than options from config:
/// the Backend key selects its , injected at construction. Adopting
/// a new FocasDriverOptions alone would poll a NEW device/tag set through the OLD backend, which
/// looks like it worked and does not.
/// ParseBinding now returns options + backend together and InitializeAsync adopts both
/// or neither. These tests pin the BACKEND moving — the half that was missing — because a test that only
/// checked options would have passed against the broken version.
///
[Trait("Category", "Unit")]
public sealed class FocasReinitConfigAdoptionTests
{
///
/// Reinitializing onto Backend: "unimplemented" must make the driver adopt that backend, whose
/// EnsureUsable() throws by design. A driver still holding the constructor's wire
/// backend would not throw — so the throw is a direct read of which backend is live.
///
[Fact]
public async Task Reinitialize_adopts_a_changed_backend_not_just_the_options()
{
var driver = FocasDriverFactoryExtensions.CreateInstance(
"focas-1", """{"backend":"wire","devices":[]}""");
var ex = await Record.ExceptionAsync(() => driver.ReinitializeAsync(
"""{"backend":"unimplemented","devices":[]}""", CancellationToken.None));
ex.ShouldBeOfType(
"FocasDriver adopted a reinitialized config but kept its ORIGINAL backend — the half-applied "
+ "adoption (#516) that would poll a new device/tag set through the old backend");
}
/// The other direction: moving OFF the unimplemented backend must also take effect, so the
/// adoption is not a one-way latch.
[Fact]
public async Task Reinitialize_away_from_the_unimplemented_backend_also_takes_effect()
{
var driver = FocasDriverFactoryExtensions.CreateInstance(
"focas-1", """{"backend":"unimplemented","devices":[]}""");
// Sanity: the constructor-supplied backend is the throwing one.
(await Record.ExceptionAsync(() => driver.InitializeAsync("{}", CancellationToken.None)))
.ShouldBeOfType();
var ex = await Record.ExceptionAsync(() => driver.ReinitializeAsync(
"""{"backend":"wire","devices":[]}""", CancellationToken.None));
ex.ShouldNotBeOfType(
"FocasDriver stayed on the unimplemented backend after a reinitialize that selected 'wire'");
}
/// An empty/placeholder document keeps the constructor-supplied pair, so the lifecycle tests
/// that pass "{}" keep meaning what they meant.
[Fact]
public async Task Reinitialize_with_an_empty_document_keeps_the_constructor_backend()
{
var driver = FocasDriverFactoryExtensions.CreateInstance(
"focas-1", """{"backend":"unimplemented","devices":[]}""");
(await Record.ExceptionAsync(() => driver.ReinitializeAsync("{}", CancellationToken.None)))
.ShouldBeOfType();
}
}