using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Client.CLI.Commands; using ZB.MOM.WW.OtOpcUa.Client.CLI.Tests.Fakes; using ZB.MOM.WW.OtOpcUa.Client.Shared.Models; namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests; public class ConnectCommandTests { [Fact] public async Task Execute_PrintsConnectionInfo() { var fakeService = new FakeOpcUaClientService { ConnectionInfoResult = new ConnectionInfo( "opc.tcp://testhost:4840", "MyServer", "SignAndEncrypt", "http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256", "session-42", "MySession") }; var factory = new FakeOpcUaClientServiceFactory(fakeService); var command = new ConnectCommand(factory) { Url = "opc.tcp://testhost:4840" }; using var console = TestConsoleHelper.CreateConsole(); await command.ExecuteAsync(console); var output = TestConsoleHelper.GetOutput(console); output.ShouldContain("Connected to: opc.tcp://testhost:4840"); output.ShouldContain("Server: MyServer"); output.ShouldContain("Security Mode: SignAndEncrypt"); output.ShouldContain("Security Policy: http://opcfoundation.org/UA/SecurityPolicy#Basic256Sha256"); output.ShouldContain("Connection successful."); } [Fact] public async Task Execute_CallsConnectAndDisconnect() { var fakeService = new FakeOpcUaClientService(); var factory = new FakeOpcUaClientServiceFactory(fakeService); var command = new ConnectCommand(factory) { Url = "opc.tcp://localhost:4840" }; using var console = TestConsoleHelper.CreateConsole(); await command.ExecuteAsync(console); fakeService.ConnectCalled.ShouldBeTrue(); fakeService.DisconnectCalled.ShouldBeTrue(); fakeService.DisposeCalled.ShouldBeTrue(); } [Fact] public async Task Execute_DisconnectsOnError() { var fakeService = new FakeOpcUaClientService { ConnectException = new InvalidOperationException("Connection refused") }; var factory = new FakeOpcUaClientServiceFactory(fakeService); var command = new ConnectCommand(factory) { Url = "opc.tcp://localhost:4840" }; using var console = TestConsoleHelper.CreateConsole(); // The command should propagate the exception but still clean up. // Since connect fails, service is null in finally, so no disconnect. await Should.ThrowAsync(async () => await command.ExecuteAsync(console)); } }