docs: backfill XML documentation across 756 files
v2-ci / build (push) Failing after 1m43s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped

Adds <summary>, <param>, <typeparam>, and <inheritdoc/> tags to public
members surfaced by commentchecker — resolves 5,847 of 5,869 issues
(99.6%) across three /fixdocs passes.
This commit is contained in:
Joseph Doherty
2026-05-28 08:10:17 -04:00
parent f9fc7dd2e1
commit 64e3fbe035
756 changed files with 9876 additions and 96 deletions
@@ -7,6 +7,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
public class AlarmsCommandTests
{
/// <summary>Verifies that Execute subscribes to alarms.</summary>
[Fact]
public async Task Execute_SubscribesToAlarms()
{
@@ -31,6 +32,7 @@ public class AlarmsCommandTests
fakeService.SubscribeAlarmsCalls[0].SourceNodeId.ShouldBeNull();
}
/// <summary>Verifies that Execute with node passes source node ID.</summary>
[Fact]
public async Task Execute_WithNode_PassesSourceNodeId()
{
@@ -55,6 +57,7 @@ public class AlarmsCommandTests
fakeService.SubscribeAlarmsCalls[0].SourceNodeId!.Identifier.ShouldBe("AlarmSource");
}
/// <summary>Verifies that Execute with refresh requests condition refresh.</summary>
[Fact]
public async Task Execute_WithRefresh_RequestsConditionRefresh()
{
@@ -79,6 +82,7 @@ public class AlarmsCommandTests
output.ShouldContain("Condition refresh requested.");
}
/// <summary>Verifies that refresh failure prints error.</summary>
[Fact]
public async Task Execute_RefreshFailure_PrintsError()
{
@@ -105,6 +109,7 @@ public class AlarmsCommandTests
output.ShouldContain("Condition refresh not supported:");
}
/// <summary>Verifies that Execute unsubscribes on cancellation.</summary>
[Fact]
public async Task Execute_UnsubscribesOnCancellation()
{
@@ -126,6 +131,7 @@ public class AlarmsCommandTests
fakeService.UnsubscribeAlarmsCalled.ShouldBeTrue();
}
/// <summary>Verifies that Execute disconnects in finally block.</summary>
[Fact]
public async Task Execute_DisconnectsInFinally()
{
@@ -8,6 +8,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
public class BrowseCommandTests
{
/// <summary>Verifies that Execute prints browse results correctly.</summary>
[Fact]
public async Task Execute_PrintsBrowseResults()
{
@@ -35,6 +36,7 @@ public class BrowseCommandTests
output.ShouldContain("[Method] Method1 (NodeId: ns=2;s=Meth1)");
}
/// <summary>Verifies that Execute browses from the specified node ID.</summary>
[Fact]
public async Task Execute_BrowsesFromSpecifiedNode()
{
@@ -57,6 +59,7 @@ public class BrowseCommandTests
fakeService.BrowseNodeIds[0]!.Identifier.ShouldBe("StartNode");
}
/// <summary>Verifies that Execute browses from null node when not specified.</summary>
[Fact]
public async Task Execute_DefaultBrowsesFromNull()
{
@@ -77,6 +80,7 @@ public class BrowseCommandTests
fakeService.BrowseNodeIds[0].ShouldBeNull();
}
/// <summary>Verifies that Execute browses only a single level when not recursive.</summary>
[Fact]
public async Task Execute_NonRecursive_BrowsesSingleLevel()
{
@@ -101,6 +105,7 @@ public class BrowseCommandTests
fakeService.BrowseNodeIds.Count.ShouldBe(1);
}
/// <summary>Verifies that Execute browses child nodes when recursive flag is set.</summary>
[Fact]
public async Task Execute_Recursive_BrowsesChildren()
{
@@ -123,6 +128,7 @@ public class BrowseCommandTests
fakeService.BrowseNodeIds.Count.ShouldBeGreaterThan(1);
}
/// <summary>Verifies that Execute disconnects and disposes in the finally block.</summary>
[Fact]
public async Task Execute_DisconnectsInFinally()
{
@@ -8,6 +8,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
public class CommandBaseTests
{
/// <summary>Verifies that common options map to connection settings correctly.</summary>
[Fact]
public async Task CommonOptions_MapToConnectionSettings_Correctly()
{
@@ -37,6 +38,7 @@ public class CommandBaseTests
settings.AutoAcceptCertificates.ShouldBeTrue();
}
/// <summary>Verifies that encrypt option maps to SignAndEncrypt.</summary>
[Fact]
public async Task SecurityOption_Encrypt_MapsToSignAndEncrypt()
{
@@ -54,6 +56,7 @@ public class CommandBaseTests
fakeService.LastConnectionSettings!.SecurityMode.ShouldBe(SecurityMode.SignAndEncrypt);
}
/// <summary>Verifies that none option maps to None.</summary>
[Fact]
public async Task SecurityOption_None_MapsToNone()
{
@@ -71,6 +74,7 @@ public class CommandBaseTests
fakeService.LastConnectionSettings!.SecurityMode.ShouldBe(SecurityMode.None);
}
/// <summary>Verifies that no failover URLs results in null FailoverUrls.</summary>
[Fact]
public async Task NoFailoverUrls_FailoverUrlsIsNull()
{
@@ -12,6 +12,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
/// </summary>
public class CommandRangeValidationTests
{
/// <summary>Verifies that BrowseCommand rejects negative depth values with a command exception.</summary>
[Fact]
public async Task BrowseCommand_NegativeDepth_ThrowsCommandException()
{
@@ -28,6 +29,7 @@ public class CommandRangeValidationTests
ex.Message.ShouldContain("--depth");
}
/// <summary>Verifies that BrowseCommand rejects zero depth values with a command exception.</summary>
[Fact]
public async Task BrowseCommand_ZeroDepth_ThrowsCommandException()
{
@@ -44,6 +46,7 @@ public class CommandRangeValidationTests
ex.Message.ShouldContain("--depth");
}
/// <summary>Verifies that SubscribeCommand rejects zero interval values with a command exception.</summary>
[Fact]
public async Task SubscribeCommand_ZeroInterval_ThrowsCommandException()
{
@@ -61,6 +64,7 @@ public class CommandRangeValidationTests
ex.Message.ShouldContain("--interval");
}
/// <summary>Verifies that SubscribeCommand rejects negative interval values with a command exception.</summary>
[Fact]
public async Task SubscribeCommand_NegativeInterval_ThrowsCommandException()
{
@@ -77,6 +81,7 @@ public class CommandRangeValidationTests
await Should.ThrowAsync<CommandException>(async () => await command.ExecuteAsync(console));
}
/// <summary>Verifies that SubscribeCommand in recursive mode rejects zero max depth with a command exception.</summary>
[Fact]
public async Task SubscribeCommand_RecursiveZeroMaxDepth_ThrowsCommandException()
{
@@ -96,6 +101,7 @@ public class CommandRangeValidationTests
ex.Message.ShouldContain("--max-depth");
}
/// <summary>Verifies that SubscribeCommand rejects negative duration values with a command exception.</summary>
[Fact]
public async Task SubscribeCommand_NegativeDuration_ThrowsCommandException()
{
@@ -112,6 +118,7 @@ public class CommandRangeValidationTests
await Should.ThrowAsync<CommandException>(async () => await command.ExecuteAsync(console));
}
/// <summary>Verifies that AlarmsCommand rejects zero interval values with a command exception.</summary>
[Fact]
public async Task AlarmsCommand_ZeroInterval_ThrowsCommandException()
{
@@ -128,6 +135,7 @@ public class CommandRangeValidationTests
ex.Message.ShouldContain("--interval");
}
/// <summary>Verifies that HistoryReadCommand rejects negative max values with a command exception.</summary>
[Fact]
public async Task HistoryReadCommand_NegativeMax_ThrowsCommandException()
{
@@ -145,6 +153,7 @@ public class CommandRangeValidationTests
ex.Message.ShouldContain("--max");
}
/// <summary>Verifies that HistoryReadCommand rejects zero interval values with a command exception.</summary>
[Fact]
public async Task HistoryReadCommand_ZeroInterval_ThrowsCommandException()
{
@@ -8,6 +8,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
public class ConnectCommandTests
{
/// <summary>Verifies that execute prints connection info.</summary>
[Fact]
public async Task Execute_PrintsConnectionInfo()
{
@@ -38,6 +39,7 @@ public class ConnectCommandTests
output.ShouldContain("Connection successful.");
}
/// <summary>Verifies that execute calls connect and disconnect.</summary>
[Fact]
public async Task Execute_CallsConnectAndDisconnect()
{
@@ -56,6 +58,7 @@ public class ConnectCommandTests
fakeService.DisposeCalled.ShouldBeTrue();
}
/// <summary>Verifies that execute disconnects on error.</summary>
[Fact]
public async Task Execute_DisconnectsOnError()
{
@@ -14,6 +14,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
/// </summary>
public class EventHandlerLifecycleTests
{
/// <summary>Verifies that SubscribeCommand detaches the DataChanged event handler after exit.</summary>
[Fact]
public async Task SubscribeCommand_AfterExit_DataChangedEventHasNoSubscribers()
{
@@ -35,6 +36,7 @@ public class EventHandlerLifecycleTests
"SubscribeCommand must detach its DataChanged handler before returning.");
}
/// <summary>Verifies that AlarmsCommand detaches the AlarmEvent handler after exit.</summary>
[Fact]
public async Task AlarmsCommand_AfterExit_AlarmEventHasNoSubscribers()
{
@@ -12,27 +12,55 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests.Fakes;
public sealed class FakeOpcUaClientService : IOpcUaClientService
{
// Track calls
/// <summary>Gets a value indicating whether ConnectAsync was called.</summary>
public bool ConnectCalled { get; private set; }
/// <summary>Gets the connection settings from the most recent ConnectAsync call.</summary>
public ConnectionSettings? LastConnectionSettings { get; private set; }
/// <summary>Gets a value indicating whether DisconnectAsync was called.</summary>
public bool DisconnectCalled { get; private set; }
/// <summary>Gets a value indicating whether Dispose was called.</summary>
public bool DisposeCalled { get; private set; }
/// <summary>Gets the list of node IDs passed to ReadValueAsync calls.</summary>
public List<NodeId> ReadNodeIds { get; } = [];
/// <summary>Gets the list of (NodeId, value) pairs passed to WriteValueAsync calls.</summary>
public List<(NodeId NodeId, object Value)> WriteValues { get; } = [];
/// <summary>Gets the list of parent node IDs passed to BrowseAsync calls.</summary>
public List<NodeId?> BrowseNodeIds { get; } = [];
/// <summary>Gets the list of (NodeId, intervalMs) pairs from SubscribeAsync calls.</summary>
public List<(NodeId NodeId, int IntervalMs)> SubscribeCalls { get; } = [];
/// <summary>Gets the list of node IDs passed to UnsubscribeAsync calls.</summary>
public List<NodeId> UnsubscribeCalls { get; } = [];
/// <summary>Gets the list of (SourceNodeId, intervalMs) pairs from SubscribeAlarmsAsync calls.</summary>
public List<(NodeId? SourceNodeId, int IntervalMs)> SubscribeAlarmsCalls { get; } = [];
/// <summary>Gets a value indicating whether UnsubscribeAlarmsAsync was called.</summary>
public bool UnsubscribeAlarmsCalled { get; private set; }
/// <summary>Gets a value indicating whether RequestConditionRefreshAsync was called.</summary>
public bool RequestConditionRefreshCalled { get; private set; }
/// <summary>Gets the list of (NodeId, start, end, maxValues) tuples from HistoryReadRawAsync calls.</summary>
public List<(NodeId NodeId, DateTime Start, DateTime End, int MaxValues)> HistoryReadRawCalls { get; } = [];
/// <summary>Gets the list of history read aggregate call parameters.</summary>
public List<(NodeId NodeId, DateTime Start, DateTime End, AggregateType Aggregate, double IntervalMs)>
HistoryReadAggregateCalls { get; } =
[];
/// <summary>Gets a value indicating whether GetRedundancyInfoAsync was called.</summary>
public bool GetRedundancyInfoCalled { get; private set; }
// Configurable results
/// <summary>Gets or sets the connection info returned by ConnectAsync.</summary>
public ConnectionInfo ConnectionInfoResult { get; set; } = new(
"opc.tcp://localhost:4840",
"TestServer",
@@ -41,14 +69,17 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
"session-1",
"TestSession");
/// <summary>Gets or sets the data value returned by ReadValueAsync.</summary>
public DataValue ReadValueResult { get; set; } = new(
new Variant(42),
StatusCodes.Good,
DateTime.UtcNow,
DateTime.UtcNow);
/// <summary>Gets or sets the status code returned by WriteValueAsync.</summary>
public StatusCode WriteStatusCodeResult { get; set; } = StatusCodes.Good;
/// <summary>Gets or sets the browse results returned by BrowseAsync.</summary>
public IReadOnlyList<BrowseResult> BrowseResults { get; set; } = new List<BrowseResult>
{
new("ns=2;s=Node1", "Node1", "Object", true),
@@ -63,19 +94,30 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
/// </summary>
public Dictionary<string, IReadOnlyList<BrowseResult>> BrowseResultsByParent { get; } = new();
/// <summary>Gets or sets the history read result returned by HistoryReadRawAsync and HistoryReadAggregateAsync.</summary>
public IReadOnlyList<DataValue> HistoryReadResult { get; set; } = new List<DataValue>
{
new(new Variant(10.0), StatusCodes.Good, DateTime.UtcNow.AddHours(-1), DateTime.UtcNow),
new(new Variant(20.0), StatusCodes.Good, DateTime.UtcNow, DateTime.UtcNow)
};
/// <summary>Gets or sets the redundancy info returned by GetRedundancyInfoAsync.</summary>
public RedundancyInfo RedundancyInfoResult { get; set; } = new(
"Warm", 200, ["urn:server1", "urn:server2"], "urn:app:test");
/// <summary>Gets or sets the exception thrown by ConnectAsync.</summary>
public Exception? ConnectException { get; set; }
/// <summary>Gets or sets the exception thrown by ReadValueAsync.</summary>
public Exception? ReadException { get; set; }
/// <summary>Gets or sets the exception thrown by WriteValueAsync.</summary>
public Exception? WriteException { get; set; }
/// <summary>Gets or sets the exception thrown by RequestConditionRefreshAsync.</summary>
public Exception? ConditionRefreshException { get; set; }
/// <summary>Gets or sets the exception thrown by SubscribeAsync.</summary>
public Exception? SubscribeException { get; set; }
/// <inheritdoc />
@@ -218,18 +260,24 @@ public sealed class FakeOpcUaClientService : IOpcUaClientService
}
/// <summary>Raises the DataChanged event for testing subscribe commands.</summary>
/// <param name="nodeId">The node ID string that changed.</param>
/// <param name="value">The new data value.</param>
public void RaiseDataChanged(string nodeId, DataValue value)
{
DataChanged?.Invoke(this, new DataChangedEventArgs(nodeId, value));
}
/// <summary>Raises the AlarmEvent for testing alarm commands.</summary>
/// <param name="args">The alarm event arguments.</param>
public void RaiseAlarmEvent(AlarmEventArgs args)
{
AlarmEvent?.Invoke(this, args);
}
/// <summary>Raises the ConnectionStateChanged event for testing.</summary>
/// <param name="oldState">The previous connection state.</param>
/// <param name="newState">The new connection state.</param>
/// <param name="endpointUrl">The endpoint URL.</param>
public void RaiseConnectionStateChanged(ConnectionState oldState, ConnectionState newState, string endpointUrl)
{
ConnectionStateChanged?.Invoke(this, new ConnectionStateChangedEventArgs(oldState, newState, endpointUrl));
@@ -9,11 +9,14 @@ public sealed class FakeOpcUaClientServiceFactory : IOpcUaClientServiceFactory
{
private readonly FakeOpcUaClientService _service;
/// <summary>Initializes a new instance of the <see cref="FakeOpcUaClientServiceFactory"/> class.</summary>
/// <param name="service">The fake OPC UA client service to return.</param>
public FakeOpcUaClientServiceFactory(FakeOpcUaClientService service)
{
_service = service;
}
/// <summary>Creates and returns the fake OPC UA client service.</summary>
public IOpcUaClientService Create()
{
return _service;
@@ -9,6 +9,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
public class HistoryReadCommandTests
{
/// <summary>Verifies RawRead execution prints values.</summary>
[Fact]
public async Task Execute_RawRead_PrintsValues()
{
@@ -42,6 +43,7 @@ public class HistoryReadCommandTests
output.ShouldContain("2 values returned.");
}
/// <summary>Verifies RawRead execution calls HistoryReadRaw.</summary>
[Fact]
public async Task Execute_RawRead_CallsHistoryReadRaw()
{
@@ -62,6 +64,7 @@ public class HistoryReadCommandTests
fakeService.HistoryReadRawCalls[0].NodeId.Identifier.ShouldBe("HistNode");
}
/// <summary>Verifies AggregateRead execution calls HistoryReadAggregate.</summary>
[Fact]
public async Task Execute_AggregateRead_CallsHistoryReadAggregate()
{
@@ -83,6 +86,7 @@ public class HistoryReadCommandTests
fakeService.HistoryReadAggregateCalls[0].IntervalMs.ShouldBe(60000);
}
/// <summary>Verifies AggregateRead execution prints aggregate info.</summary>
[Fact]
public async Task Execute_AggregateRead_PrintsAggregateInfo()
{
@@ -104,6 +108,7 @@ public class HistoryReadCommandTests
output.ShouldContain("7200000");
}
/// <summary>Verifies invalid aggregate throws CommandException.</summary>
[Fact]
public async Task Execute_InvalidAggregate_ThrowsCommandException()
{
@@ -123,6 +128,7 @@ public class HistoryReadCommandTests
async () => await command.ExecuteAsync(console));
}
/// <summary>Verifies disconnect is called in finally block.</summary>
[Fact]
public async Task Execute_DisconnectsInFinally()
{
@@ -13,6 +13,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
/// </summary>
public class InputValidationErrorsTests
{
/// <summary>Verifies that HistoryReadCommand with invalid start time throws CommandException.</summary>
[Fact]
public async Task HistoryReadCommand_InvalidStartTime_ThrowsCommandException()
{
@@ -30,6 +31,7 @@ public class InputValidationErrorsTests
ex.Message.ShouldContain("--start");
}
/// <summary>Verifies that HistoryReadCommand with invalid end time throws CommandException.</summary>
[Fact]
public async Task HistoryReadCommand_InvalidEndTime_ThrowsCommandException()
{
@@ -47,6 +49,7 @@ public class InputValidationErrorsTests
ex.Message.ShouldContain("--end");
}
/// <summary>Verifies that HistoryReadCommand with invalid aggregate throws CommandException.</summary>
[Fact]
public async Task HistoryReadCommand_InvalidAggregate_ThrowsCommandException()
{
@@ -64,6 +67,7 @@ public class InputValidationErrorsTests
ex.Message.ShouldContain("aggregate", Case.Insensitive);
}
/// <summary>Verifies that ReadCommand with invalid node ID throws CommandException.</summary>
[Fact]
public async Task ReadCommand_InvalidNodeId_ThrowsCommandException()
{
@@ -80,6 +84,7 @@ public class InputValidationErrorsTests
ex.Message.ShouldContain("node", Case.Insensitive);
}
/// <summary>Verifies that SubscribeCommand with invalid node ID throws CommandException.</summary>
[Fact]
public async Task SubscribeCommand_InvalidNodeId_ThrowsCommandException()
{
@@ -14,6 +14,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
/// </summary>
public class LoggerLifecycleTests
{
/// <summary>Verifies that ConfigureLogging disposes previous logger before reassigning.</summary>
[Fact]
public async Task ConfigureLogging_DisposesPreviousLogger_BeforeReassigning()
{
@@ -48,8 +49,12 @@ public class LoggerLifecycleTests
private sealed class DisposeTrackingSink : ILogEventSink, IDisposable
{
/// <summary>Gets a value indicating whether the sink has been disposed.</summary>
public bool Disposed { get; private set; }
/// <summary>Emits a log event.</summary>
/// <param name="logEvent">The log event to emit.</param>
public void Emit(LogEvent logEvent) { }
/// <summary>Disposes the sink and marks it as disposed.</summary>
public void Dispose() => Disposed = true;
}
}
@@ -7,24 +7,28 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
public class NodeIdParserTests
{
/// <summary>Verifies that Parse returns null for null input.</summary>
[Fact]
public void Parse_NullInput_ReturnsNull()
{
NodeIdParser.Parse(null).ShouldBeNull();
}
/// <summary>Verifies that Parse returns null for empty string input.</summary>
[Fact]
public void Parse_EmptyString_ReturnsNull()
{
NodeIdParser.Parse("").ShouldBeNull();
}
/// <summary>Verifies that Parse returns null for whitespace-only input.</summary>
[Fact]
public void Parse_WhitespaceOnly_ReturnsNull()
{
NodeIdParser.Parse(" ").ShouldBeNull();
}
/// <summary>Verifies that Parse correctly parses standard NodeId format (ns=2;s=MyNode).</summary>
[Fact]
public void Parse_StandardStringFormat_ReturnsNodeId()
{
@@ -34,6 +38,7 @@ public class NodeIdParserTests
result.Identifier.ShouldBe("MyNode");
}
/// <summary>Verifies that Parse correctly parses numeric NodeId format (i=85).</summary>
[Fact]
public void Parse_NumericFormat_ReturnsNodeId()
{
@@ -42,6 +47,7 @@ public class NodeIdParserTests
result.IdType.ShouldBe(IdType.Numeric);
}
/// <summary>Verifies that Parse treats bare numeric input as namespace 0 numeric NodeId.</summary>
[Fact]
public void Parse_BareNumeric_ReturnsNamespace0NumericNodeId()
{
@@ -51,6 +57,7 @@ public class NodeIdParserTests
result.Identifier.ShouldBe((uint)85);
}
/// <summary>Verifies that Parse trims whitespace padding from input.</summary>
[Fact]
public void Parse_WithWhitespacePadding_Trims()
{
@@ -59,24 +66,28 @@ public class NodeIdParserTests
result.Identifier.ShouldBe("MyNode");
}
/// <summary>Verifies that Parse throws FormatException for invalid input.</summary>
[Fact]
public void Parse_InvalidFormat_ThrowsFormatException()
{
Should.Throw<FormatException>(() => NodeIdParser.Parse("not-a-node-id"));
}
/// <summary>Verifies that ParseRequired throws ArgumentException for null input.</summary>
[Fact]
public void ParseRequired_NullInput_ThrowsArgumentException()
{
Should.Throw<ArgumentException>(() => NodeIdParser.ParseRequired(null));
}
/// <summary>Verifies that ParseRequired throws ArgumentException for empty input.</summary>
[Fact]
public void ParseRequired_EmptyInput_ThrowsArgumentException()
{
Should.Throw<ArgumentException>(() => NodeIdParser.ParseRequired(""));
}
/// <summary>Verifies that ParseRequired returns a NodeId for valid input.</summary>
[Fact]
public void ParseRequired_ValidInput_ReturnsNodeId()
{
@@ -8,6 +8,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
public class ReadCommandTests
{
/// <summary>Verifies that execute prints the read value.</summary>
[Fact]
public async Task Execute_PrintsReadValue()
{
@@ -39,6 +40,7 @@ public class ReadCommandTests
output.ShouldContain("Server Time:");
}
/// <summary>Verifies that execute calls read value with correct node ID.</summary>
[Fact]
public async Task Execute_CallsReadValueWithCorrectNodeId()
{
@@ -57,6 +59,7 @@ public class ReadCommandTests
fakeService.ReadNodeIds[0].Identifier.ShouldBe("MyVariable");
}
/// <summary>Verifies that execute disconnects in finally.</summary>
[Fact]
public async Task Execute_DisconnectsInFinally()
{
@@ -75,6 +78,7 @@ public class ReadCommandTests
fakeService.DisposeCalled.ShouldBeTrue();
}
/// <summary>Verifies that execute disconnects even on read error.</summary>
[Fact]
public async Task Execute_DisconnectsEvenOnReadError()
{
@@ -8,6 +8,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
public class RedundancyCommandTests
{
/// <summary>Verifies that Execute prints redundancy information correctly.</summary>
[Fact]
public async Task Execute_PrintsRedundancyInfo()
{
@@ -34,6 +35,7 @@ public class RedundancyCommandTests
output.ShouldContain("Application URI: urn:app:myserver");
}
/// <summary>Verifies that Execute omits the Server URIs section when none are present.</summary>
[Fact]
public async Task Execute_NoServerUris_OmitsUriSection()
{
@@ -58,6 +60,7 @@ public class RedundancyCommandTests
output.ShouldContain("Application URI: urn:app:standalone");
}
/// <summary>Verifies that Execute calls GetRedundancyInfo on the service.</summary>
[Fact]
public async Task Execute_CallsGetRedundancyInfo()
{
@@ -74,6 +77,7 @@ public class RedundancyCommandTests
fakeService.GetRedundancyInfoCalled.ShouldBeTrue();
}
/// <summary>Verifies that Execute disconnects and disposes in the finally block.</summary>
[Fact]
public async Task Execute_DisconnectsInFinally()
{
@@ -13,6 +13,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
/// </summary>
public class SubscribeCommandSummaryTests
{
/// <summary>Verifies that nodes with no updates are counted separately from suspects.</summary>
[Fact]
public async Task Summary_NodeWithNoUpdate_IsCountedAsNeverNotAsNeverWentBad()
{
@@ -39,6 +40,7 @@ public class SubscribeCommandSummaryTests
output.ShouldContain("--- Nodes that never received an update at all ---");
}
/// <summary>Verifies that nodes with only good values are counted as never went bad.</summary>
[Fact]
public async Task Summary_NodeReceivedOnlyGoodValues_IsCountedAsNeverWentBad()
{
@@ -70,6 +72,7 @@ public class SubscribeCommandSummaryTests
output.ShouldContain("No update received at all: 0");
}
/// <summary>Verifies that nodes with bad values are counted as ever went bad.</summary>
[Fact]
public async Task Summary_NodeReceivedBadValue_IsCountedAsEverWentBad()
{
@@ -98,6 +101,7 @@ public class SubscribeCommandSummaryTests
output.ShouldContain("NEVER went bad (suspect): 0");
}
/// <summary>Verifies that subscription auto-exits when duration expires.</summary>
[Fact]
public async Task Duration_ZeroOrPositive_AutoExits()
{
@@ -124,6 +128,7 @@ public class SubscribeCommandSummaryTests
output.ShouldContain("==================== SUMMARY ====================");
}
/// <summary>Verifies that --quiet suppresses updates but prints summary.</summary>
[Fact]
public async Task Quiet_SuppressesPerUpdateOutputButPrintsSummary()
{
@@ -154,6 +159,7 @@ public class SubscribeCommandSummaryTests
output.ShouldContain("==================== SUMMARY ====================");
}
/// <summary>Verifies that summary is written to disk when summary file is specified.</summary>
[Fact]
public async Task SummaryFile_WritesSummaryToDisk()
{
@@ -184,6 +190,7 @@ public class SubscribeCommandSummaryTests
}
}
/// <summary>Verifies that recursive flag browses subtree and subscribes every variable.</summary>
[Fact]
public async Task Recursive_BrowsesSubtreeAndSubscribesEveryVariable()
{
@@ -222,6 +229,7 @@ public class SubscribeCommandSummaryTests
output.ShouldContain("Browsing subtree of ns=2;s=Root");
}
/// <summary>Verifies that subscription failures are handled gracefully.</summary>
[Fact]
public async Task SubscribeFailure_PrintsFailedMessage_DoesNotCrash()
{
@@ -7,6 +7,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
public class SubscribeCommandTests
{
/// <summary>Verifies that ExecuteAsync subscribes with the correct parameters.</summary>
[Fact]
public async Task Execute_SubscribesWithCorrectParameters()
{
@@ -35,6 +36,7 @@ public class SubscribeCommandTests
fakeService.SubscribeCalls[0].NodeId.Identifier.ShouldBe("TestVar");
}
/// <summary>Verifies that ExecuteAsync unsubscribes when cancellation is requested.</summary>
[Fact]
public async Task Execute_UnsubscribesOnCancellation()
{
@@ -57,6 +59,7 @@ public class SubscribeCommandTests
fakeService.UnsubscribeCalls.Count.ShouldBe(1);
}
/// <summary>Verifies that ExecuteAsync disconnects and disposes in a finally block.</summary>
[Fact]
public async Task Execute_DisconnectsInFinally()
{
@@ -80,6 +83,7 @@ public class SubscribeCommandTests
fakeService.DisposeCalled.ShouldBeTrue();
}
/// <summary>Verifies that ExecuteAsync prints the correct subscription message.</summary>
[Fact]
public async Task Execute_PrintsSubscriptionMessage()
{
@@ -18,6 +18,8 @@ public static class TestConsoleHelper
/// <summary>
/// Reads all text written to the console's standard output.
/// </summary>
/// <param name="console">The fake console instance.</param>
/// <returns>The console output text.</returns>
public static string GetOutput(FakeInMemoryConsole console)
{
console.Output.Flush();
@@ -27,6 +29,8 @@ public static class TestConsoleHelper
/// <summary>
/// Reads all text written to the console's standard error.
/// </summary>
/// <param name="console">The fake console instance.</param>
/// <returns>The console error text.</returns>
public static string GetError(FakeInMemoryConsole console)
{
console.Error.Flush();
@@ -8,6 +8,7 @@ namespace ZB.MOM.WW.OtOpcUa.Client.CLI.Tests;
public class WriteCommandTests
{
/// <summary>Verifies that write command executes successfully.</summary>
[Fact]
public async Task Execute_WritesSuccessfully()
{
@@ -31,6 +32,7 @@ public class WriteCommandTests
output.ShouldContain("Write successful: ns=2;s=MyVar = 100");
}
/// <summary>Verifies that write command reports failure.</summary>
[Fact]
public async Task Execute_ReportsFailure()
{
@@ -54,6 +56,7 @@ public class WriteCommandTests
output.ShouldContain("Write failed:");
}
/// <summary>Verifies that write command reads current value before writing.</summary>
[Fact]
public async Task Execute_ReadsCurrentValueThenWrites()
{
@@ -79,6 +82,7 @@ public class WriteCommandTests
fakeService.WriteValues[0].Value.ShouldBeOfType<double>();
}
/// <summary>Verifies that write command disconnects in finally block.</summary>
[Fact]
public async Task Execute_DisconnectsInFinally()
{