Document client stack XML docs progress
This commit is contained in:
@@ -6,27 +6,81 @@ using BrowseResult = ZB.MOM.WW.LmxOpcUa.Client.Shared.Models.BrowseResult;
|
||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Tests.Fakes;
|
||||
|
||||
/// <summary>
|
||||
/// Fake IOpcUaClientService for unit testing.
|
||||
/// Test double for the shared OPC UA client service used by UI view-model tests.
|
||||
/// It lets tests script connection, browse, history, redundancy, and alarm behavior without a live server.
|
||||
/// </summary>
|
||||
public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
{
|
||||
// Configurable responses
|
||||
/// <summary>
|
||||
/// Gets or sets the connection metadata returned when a UI test performs a successful connect.
|
||||
/// </summary>
|
||||
public ConnectionInfo? ConnectResult { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the exception thrown to simulate a failed connect workflow in the UI.
|
||||
/// </summary>
|
||||
public Exception? ConnectException { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default browse results returned when no parent-specific branch is configured.
|
||||
/// </summary>
|
||||
public IReadOnlyList<BrowseResult> BrowseResults { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets browse results keyed by parent node so tree-navigation tests can model multiple address-space branches.
|
||||
/// </summary>
|
||||
public Dictionary<string, IReadOnlyList<BrowseResult>> BrowseResultsByParent { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the exception thrown to simulate browse failures in the UI tree.
|
||||
/// </summary>
|
||||
public Exception? BrowseException { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current value returned by point-read tests.
|
||||
/// </summary>
|
||||
public DataValue ReadResult { get; set; } =
|
||||
new(new Variant(42), StatusCodes.Good, DateTime.UtcNow, DateTime.UtcNow);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the exception thrown to simulate point-read failures in the UI.
|
||||
/// </summary>
|
||||
public Exception? ReadException { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the status code returned by write operations in UI tests.
|
||||
/// </summary>
|
||||
public StatusCode WriteResult { get; set; } = StatusCodes.Good;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the exception thrown to simulate failed write workflows in the UI.
|
||||
/// </summary>
|
||||
public Exception? WriteException { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the redundancy snapshot returned when the UI inspects server redundancy state.
|
||||
/// </summary>
|
||||
public RedundancyInfo? RedundancyResult { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the exception thrown to simulate redundancy lookup failures.
|
||||
/// </summary>
|
||||
public Exception? RedundancyException { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the raw historical values returned to history-view tests.
|
||||
/// </summary>
|
||||
public IReadOnlyList<DataValue> HistoryRawResult { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the aggregate historical values returned to history-view tests.
|
||||
/// </summary>
|
||||
public IReadOnlyList<DataValue> HistoryAggregateResult { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the exception thrown to simulate historical-data failures in the UI.
|
||||
/// </summary>
|
||||
public Exception? HistoryException { get; set; }
|
||||
|
||||
// Call tracking
|
||||
@@ -54,13 +108,22 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
public NodeId? LastUnsubscribeNodeId { get; private set; }
|
||||
public AggregateType? LastAggregateType { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsConnected { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ConnectionInfo? CurrentConnectionInfo { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<DataChangedEventArgs>? DataChanged;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<AlarmEventArgs>? AlarmEvent;
|
||||
|
||||
/// <inheritdoc />
|
||||
public event EventHandler<ConnectionStateChangedEventArgs>? ConnectionStateChanged;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<ConnectionInfo> ConnectAsync(ConnectionSettings settings, CancellationToken ct = default)
|
||||
{
|
||||
ConnectCallCount++;
|
||||
@@ -71,6 +134,7 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
return Task.FromResult(ConnectResult!);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task DisconnectAsync(CancellationToken ct = default)
|
||||
{
|
||||
DisconnectCallCount++;
|
||||
@@ -79,6 +143,7 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<DataValue> ReadValueAsync(NodeId nodeId, CancellationToken ct = default)
|
||||
{
|
||||
ReadCallCount++;
|
||||
@@ -87,6 +152,7 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
return Task.FromResult(ReadResult);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<StatusCode> WriteValueAsync(NodeId nodeId, object value, CancellationToken ct = default)
|
||||
{
|
||||
WriteCallCount++;
|
||||
@@ -96,6 +162,7 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
return Task.FromResult(WriteResult);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IReadOnlyList<BrowseResult>> BrowseAsync(NodeId? parentNodeId = null, CancellationToken ct = default)
|
||||
{
|
||||
BrowseCallCount++;
|
||||
@@ -108,6 +175,7 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
return Task.FromResult(BrowseResults);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SubscribeAsync(NodeId nodeId, int intervalMs = 1000, CancellationToken ct = default)
|
||||
{
|
||||
SubscribeCallCount++;
|
||||
@@ -116,6 +184,7 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task UnsubscribeAsync(NodeId nodeId, CancellationToken ct = default)
|
||||
{
|
||||
UnsubscribeCallCount++;
|
||||
@@ -123,18 +192,21 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task SubscribeAlarmsAsync(NodeId? sourceNodeId = null, int intervalMs = 1000, CancellationToken ct = default)
|
||||
{
|
||||
SubscribeAlarmsCallCount++;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task UnsubscribeAlarmsAsync(CancellationToken ct = default)
|
||||
{
|
||||
UnsubscribeAlarmsCallCount++;
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task RequestConditionRefreshAsync(CancellationToken ct = default)
|
||||
{
|
||||
RequestConditionRefreshCallCount++;
|
||||
@@ -145,6 +217,7 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
public Exception? AcknowledgeException { get; set; }
|
||||
public int AcknowledgeCallCount { get; private set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<StatusCode> AcknowledgeAlarmAsync(string conditionNodeId, byte[] eventId, string comment,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
@@ -153,6 +226,7 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
return Task.FromResult(AcknowledgeResult);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IReadOnlyList<DataValue>> HistoryReadRawAsync(NodeId nodeId, DateTime startTime, DateTime endTime,
|
||||
int maxValues = 1000, CancellationToken ct = default)
|
||||
{
|
||||
@@ -161,6 +235,7 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
return Task.FromResult(HistoryRawResult);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IReadOnlyList<DataValue>> HistoryReadAggregateAsync(NodeId nodeId, DateTime startTime, DateTime endTime,
|
||||
AggregateType aggregate, double intervalMs = 3600000, CancellationToken ct = default)
|
||||
{
|
||||
@@ -170,6 +245,7 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
return Task.FromResult(HistoryAggregateResult);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<RedundancyInfo> GetRedundancyInfoAsync(CancellationToken ct = default)
|
||||
{
|
||||
GetRedundancyInfoCallCount++;
|
||||
@@ -177,24 +253,35 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
|
||||
return Task.FromResult(RedundancyResult!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases fake service resources at the end of a UI test run.
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// No-op for testing
|
||||
}
|
||||
|
||||
// Methods to raise events from tests
|
||||
/// <summary>
|
||||
/// Raises a simulated data-change notification so UI tests can validate live update handling.
|
||||
/// </summary>
|
||||
public void RaiseDataChanged(DataChangedEventArgs args)
|
||||
{
|
||||
DataChanged?.Invoke(this, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises a simulated alarm event so UI tests can validate alarm-list behavior.
|
||||
/// </summary>
|
||||
public void RaiseAlarmEvent(AlarmEventArgs args)
|
||||
{
|
||||
AlarmEvent?.Invoke(this, args);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises a simulated connection-state transition so UI tests can validate status presentation and failover behavior.
|
||||
/// </summary>
|
||||
public void RaiseConnectionStateChanged(ConnectionStateChangedEventArgs args)
|
||||
{
|
||||
ConnectionStateChanged?.Invoke(this, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,9 @@ using ConnectionState = ZB.MOM.WW.LmxOpcUa.Client.Shared.Models.ConnectionState;
|
||||
|
||||
namespace ZB.MOM.WW.LmxOpcUa.Client.UI.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the main UI shell behavior for connection state, settings persistence, browsing, subscriptions, and history navigation.
|
||||
/// </summary>
|
||||
public class MainWindowViewModelTests
|
||||
{
|
||||
private readonly FakeOpcUaClientService _service;
|
||||
@@ -39,6 +42,9 @@ public class MainWindowViewModelTests
|
||||
_vm = new MainWindowViewModel(factory, dispatcher, _settingsService);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the shell starts disconnected with the default endpoint and status text.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void DefaultState_IsDisconnected()
|
||||
{
|
||||
@@ -48,18 +54,27 @@ public class MainWindowViewModelTests
|
||||
_vm.StatusMessage.ShouldBe("Disconnected");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the connect command is available before a session is established.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void ConnectCommand_CanExecute_WhenDisconnected()
|
||||
{
|
||||
_vm.ConnectCommand.CanExecute(null).ShouldBeTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that disconnect is disabled until a server session is active.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void DisconnectCommand_CannotExecute_WhenDisconnected()
|
||||
{
|
||||
_vm.DisconnectCommand.CanExecute(null).ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that a successful connect command updates the shell into the connected state.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_TransitionsToConnected()
|
||||
{
|
||||
@@ -70,6 +85,9 @@ public class MainWindowViewModelTests
|
||||
_service.ConnectCallCount.ShouldBe(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the initial browse tree is loaded after a successful connect.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_LoadsRootNodes()
|
||||
{
|
||||
@@ -79,6 +97,9 @@ public class MainWindowViewModelTests
|
||||
_vm.BrowseTree.RootNodes[0].DisplayName.ShouldBe("Root");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that redundancy details are fetched and exposed after connecting.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_FetchesRedundancyInfo()
|
||||
{
|
||||
@@ -89,6 +110,9 @@ public class MainWindowViewModelTests
|
||||
_vm.RedundancyInfo.ServiceLevel.ShouldBe((byte)200);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the session label shows the connected server and session identity.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_SetsSessionLabel()
|
||||
{
|
||||
@@ -98,6 +122,9 @@ public class MainWindowViewModelTests
|
||||
_vm.SessionLabel.ShouldContain("TestSession");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that disconnect returns the shell to the disconnected state.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task DisconnectCommand_TransitionsToDisconnected()
|
||||
{
|
||||
@@ -109,6 +136,9 @@ public class MainWindowViewModelTests
|
||||
_service.DisconnectCallCount.ShouldBe(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that disconnect clears session-specific UI state such as browse data and redundancy details.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task Disconnect_ClearsStateAndChildren()
|
||||
{
|
||||
@@ -121,6 +151,9 @@ public class MainWindowViewModelTests
|
||||
_vm.SubscriptionCount.ShouldBe(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that connection-state events from the client update the shell status text and state.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectionStateChangedEvent_UpdatesState()
|
||||
{
|
||||
@@ -134,6 +167,9 @@ public class MainWindowViewModelTests
|
||||
_vm.StatusMessage.ShouldBe("Reconnecting...");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that selecting a tree node updates the dependent read/write and history panels.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task SelectedTreeNode_PropagatesToChildViewModels()
|
||||
{
|
||||
@@ -146,6 +182,9 @@ public class MainWindowViewModelTests
|
||||
_vm.History.SelectedNodeId.ShouldBe(node.NodeId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that a successful connect propagates connected state into the child tabs.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_PropagatesIsConnectedToChildViewModels()
|
||||
{
|
||||
@@ -157,6 +196,9 @@ public class MainWindowViewModelTests
|
||||
_vm.History.IsConnected.ShouldBeTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that disconnect propagates disconnected state into the child tabs.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task DisconnectCommand_PropagatesIsConnectedFalseToChildViewModels()
|
||||
{
|
||||
@@ -169,6 +211,9 @@ public class MainWindowViewModelTests
|
||||
_vm.History.IsConnected.ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that failed connection attempts restore the disconnected shell state and surface the error text.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectFailure_RevertsToDisconnected()
|
||||
{
|
||||
@@ -180,6 +225,9 @@ public class MainWindowViewModelTests
|
||||
_vm.StatusMessage.ShouldContain("Connection refused");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that connection-state transitions raise property-changed notifications for UI binding updates.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task PropertyChanged_FiredForConnectionState()
|
||||
{
|
||||
@@ -195,6 +243,9 @@ public class MainWindowViewModelTests
|
||||
changed.ShouldContain(nameof(MainWindowViewModel.ConnectionState));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the shell initializes advanced connection settings with the expected defaults.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void DefaultState_HasCorrectAdvancedSettings()
|
||||
{
|
||||
@@ -205,6 +256,9 @@ public class MainWindowViewModelTests
|
||||
_vm.CertificateStorePath.ShouldContain("pki");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that failover endpoint text is parsed into connection settings on connect.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_MapsFailoverUrlsToSettings()
|
||||
{
|
||||
@@ -218,6 +272,9 @@ public class MainWindowViewModelTests
|
||||
_service.LastConnectionSettings.FailoverUrls[1].ShouldBe("opc.tcp://backup2:4840");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that empty failover text is normalized to no configured failover endpoints.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_MapsEmptyFailoverUrlsToNull()
|
||||
{
|
||||
@@ -228,6 +285,9 @@ public class MainWindowViewModelTests
|
||||
_service.LastConnectionSettings!.FailoverUrls.ShouldBeNull();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the configured session timeout is passed into the connection settings.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_MapsSessionTimeoutToSettings()
|
||||
{
|
||||
@@ -238,6 +298,9 @@ public class MainWindowViewModelTests
|
||||
_service.LastConnectionSettings!.SessionTimeoutSeconds.ShouldBe(120);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the auto-accept certificate toggle is passed into the connection settings.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_MapsAutoAcceptCertificatesToSettings()
|
||||
{
|
||||
@@ -248,6 +311,9 @@ public class MainWindowViewModelTests
|
||||
_service.LastConnectionSettings!.AutoAcceptCertificates.ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that a custom certificate store path is passed into the connection settings.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_MapsCertificateStorePathToSettings()
|
||||
{
|
||||
@@ -258,6 +324,9 @@ public class MainWindowViewModelTests
|
||||
_service.LastConnectionSettings!.CertificateStorePath.ShouldBe("/custom/pki/path");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that subscribing selected nodes adds subscriptions and switches the shell to the subscriptions tab.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task SubscribeSelectedNodesCommand_SubscribesAndSwitchesToTab()
|
||||
{
|
||||
@@ -275,6 +344,9 @@ public class MainWindowViewModelTests
|
||||
_vm.SelectedTabIndex.ShouldBe(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that subscribing selected nodes is a no-op when nothing is selected.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task SubscribeSelectedNodesCommand_DoesNothing_WhenNoSelection()
|
||||
{
|
||||
@@ -285,6 +357,9 @@ public class MainWindowViewModelTests
|
||||
_vm.Subscriptions.ActiveSubscriptions.ShouldBeEmpty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the history command targets the selected node and switches the shell to the history tab.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ViewHistoryForSelectedNodeCommand_SetsNodeAndSwitchesToTab()
|
||||
{
|
||||
@@ -299,6 +374,9 @@ public class MainWindowViewModelTests
|
||||
_vm.SelectedTabIndex.ShouldBe(3);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that history actions are enabled when a variable node is selected.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UpdateHistoryEnabledForSelection_TrueForVariableNode()
|
||||
{
|
||||
@@ -313,6 +391,9 @@ public class MainWindowViewModelTests
|
||||
_vm.IsHistoryEnabledForSelection.ShouldBeTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that history actions stay disabled when an object node rather than a variable is selected.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task UpdateHistoryEnabledForSelection_FalseForObjectNode()
|
||||
{
|
||||
@@ -327,6 +408,9 @@ public class MainWindowViewModelTests
|
||||
_vm.IsHistoryEnabledForSelection.ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that history actions stay disabled when no server connection is active.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void UpdateHistoryEnabledForSelection_FalseWhenDisconnected()
|
||||
{
|
||||
@@ -335,12 +419,18 @@ public class MainWindowViewModelTests
|
||||
_vm.IsHistoryEnabledForSelection.ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that saved user settings are loaded during shell construction.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Constructor_LoadsSettingsFromService()
|
||||
{
|
||||
_settingsService.LoadCallCount.ShouldBe(1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that persisted connection and security settings are applied to the shell on startup.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void Constructor_AppliesSavedSettings()
|
||||
{
|
||||
@@ -376,6 +466,9 @@ public class MainWindowViewModelTests
|
||||
vm.CertificateStorePath.ShouldBe("/custom/path");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that successful connections persist the current connection settings.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_SavesSettingsOnSuccess()
|
||||
{
|
||||
@@ -390,6 +483,9 @@ public class MainWindowViewModelTests
|
||||
_settingsService.LastSaved.Username.ShouldBe("admin");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that failed connection attempts do not overwrite saved settings.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_DoesNotSaveOnFailure()
|
||||
{
|
||||
@@ -400,6 +496,9 @@ public class MainWindowViewModelTests
|
||||
_settingsService.SaveCallCount.ShouldBe(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that active subscriptions are persisted when the shell disconnects.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_SavesSubscribedNodes()
|
||||
{
|
||||
@@ -416,6 +515,9 @@ public class MainWindowViewModelTests
|
||||
_settingsService.LastSaved!.SubscribedNodes.ShouldContain("ns=2;s=TestSub");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that saved subscriptions are restored after reconnecting the shell.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ConnectCommand_RestoresSavedSubscriptions()
|
||||
{
|
||||
@@ -437,4 +539,4 @@ public class MainWindowViewModelTests
|
||||
vm.Subscriptions.ActiveSubscriptions[1].NodeId.ShouldBe("ns=2;s=Restored2");
|
||||
vm.SubscriptionCount.ShouldBe(2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user