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
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:
@@ -7,6 +7,9 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientAlarmTests
|
||||
{
|
||||
/// <summary>Verifies that MapSeverity buckets per OPC UA Part 9 guidance.</summary>
|
||||
/// <param name="opcSev">The OPC UA severity value (1–1000).</param>
|
||||
/// <param name="expected">The expected mapped alarm severity.</param>
|
||||
[Theory]
|
||||
[InlineData((ushort)1, AlarmSeverity.Low)]
|
||||
[InlineData((ushort)200, AlarmSeverity.Low)]
|
||||
@@ -21,6 +24,7 @@ public sealed class OpcUaClientAlarmTests
|
||||
OpcUaClientDriver.MapSeverity(opcSev).ShouldBe(expected);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that MapSeverity zero maps to Low.</summary>
|
||||
[Fact]
|
||||
public void MapSeverity_zero_maps_to_Low()
|
||||
{
|
||||
@@ -28,6 +32,7 @@ public sealed class OpcUaClientAlarmTests
|
||||
OpcUaClientDriver.MapSeverity(0).ShouldBe(AlarmSeverity.Low);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that SubscribeAlarmsAsync without initialize throws InvalidOperationException.</summary>
|
||||
[Fact]
|
||||
public async Task SubscribeAlarmsAsync_without_initialize_throws_InvalidOperationException()
|
||||
{
|
||||
@@ -36,6 +41,7 @@ public sealed class OpcUaClientAlarmTests
|
||||
await drv.SubscribeAlarmsAsync([], TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that UnsubscribeAlarmsAsync with unknown handle is noop.</summary>
|
||||
[Fact]
|
||||
public async Task UnsubscribeAlarmsAsync_with_unknown_handle_is_noop()
|
||||
{
|
||||
@@ -44,6 +50,7 @@ public sealed class OpcUaClientAlarmTests
|
||||
await drv.UnsubscribeAlarmsAsync(new FakeAlarmHandle(), TestContext.Current.CancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that AcknowledgeAsync without initialize throws InvalidOperationException.</summary>
|
||||
[Fact]
|
||||
public async Task AcknowledgeAsync_without_initialize_throws_InvalidOperationException()
|
||||
{
|
||||
@@ -54,6 +61,7 @@ public sealed class OpcUaClientAlarmTests
|
||||
TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that AcknowledgeAsync with empty batch is noop even without init.</summary>
|
||||
[Fact]
|
||||
public async Task AcknowledgeAsync_with_empty_batch_is_noop_even_without_init()
|
||||
{
|
||||
@@ -65,6 +73,7 @@ public sealed class OpcUaClientAlarmTests
|
||||
|
||||
private sealed class FakeAlarmHandle : IAlarmSubscriptionHandle
|
||||
{
|
||||
/// <summary>Gets the diagnostic identifier for this alarm handle.</summary>
|
||||
public string DiagnosticId => "fake-alarm";
|
||||
}
|
||||
}
|
||||
|
||||
+10
@@ -8,6 +8,9 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientAttributeMappingTests
|
||||
{
|
||||
/// <summary>Verifies that MapUpstreamDataType recognizes standard builtin OPC UA types.</summary>
|
||||
/// <param name="typeId">The OPC UA data type ID.</param>
|
||||
/// <param name="expected">The expected driver data type.</param>
|
||||
[Theory]
|
||||
[InlineData((uint)DataTypes.Boolean, DriverDataType.Boolean)]
|
||||
[InlineData((uint)DataTypes.SByte, DriverDataType.Int16)]
|
||||
@@ -28,6 +31,7 @@ public sealed class OpcUaClientAttributeMappingTests
|
||||
OpcUaClientDriver.MapUpstreamDataType(nodeId).ShouldBe(expected);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that MapUpstreamDataType maps SByte to Int16 since DriverDataType lacks 8-bit signed.</summary>
|
||||
[Fact]
|
||||
public void MapUpstreamDataType_maps_SByte_to_Int16_since_DriverDataType_lacks_8bit_signed()
|
||||
{
|
||||
@@ -35,6 +39,7 @@ public sealed class OpcUaClientAttributeMappingTests
|
||||
OpcUaClientDriver.MapUpstreamDataType(new NodeId((uint)DataTypes.SByte)).ShouldBe(DriverDataType.Int16);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that MapUpstreamDataType maps Byte to UInt16 not Int16.</summary>
|
||||
[Fact]
|
||||
public void MapUpstreamDataType_maps_Byte_to_UInt16_not_Int16()
|
||||
{
|
||||
@@ -44,6 +49,7 @@ public sealed class OpcUaClientAttributeMappingTests
|
||||
OpcUaClientDriver.MapUpstreamDataType(new NodeId((uint)DataTypes.Byte)).ShouldBe(DriverDataType.UInt16);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that MapUpstreamDataType falls back to String for unknown custom types.</summary>
|
||||
[Fact]
|
||||
public void MapUpstreamDataType_falls_back_to_String_for_unknown_custom_types()
|
||||
{
|
||||
@@ -51,12 +57,16 @@ public sealed class OpcUaClientAttributeMappingTests
|
||||
OpcUaClientDriver.MapUpstreamDataType(new NodeId("CustomStruct", 2)).ShouldBe(DriverDataType.String);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that MapUpstreamDataType handles UtcTime as DateTime.</summary>
|
||||
[Fact]
|
||||
public void MapUpstreamDataType_handles_UtcTime_as_DateTime()
|
||||
{
|
||||
OpcUaClientDriver.MapUpstreamDataType(new NodeId((uint)DataTypes.UtcTime)).ShouldBe(DriverDataType.DateTime);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that MapAccessLevelToSecurityClass respects the CurrentWrite bit.</summary>
|
||||
/// <param name="accessLevel">The access level byte.</param>
|
||||
/// <param name="expected">The expected security classification.</param>
|
||||
[Theory]
|
||||
[InlineData((byte)0, SecurityClassification.ViewOnly)] // no access flags set
|
||||
[InlineData((byte)1, SecurityClassification.ViewOnly)] // CurrentRead only
|
||||
|
||||
@@ -8,6 +8,9 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientCertAuthTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Verifies that BuildCertificateIdentity rejects missing certificate path.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void BuildCertificateIdentity_rejects_missing_path()
|
||||
{
|
||||
@@ -16,6 +19,9 @@ public sealed class OpcUaClientCertAuthTests
|
||||
.Message.ShouldContain("UserCertificatePath");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that BuildCertificateIdentity rejects nonexistent certificate file.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void BuildCertificateIdentity_rejects_nonexistent_file()
|
||||
{
|
||||
@@ -27,6 +33,9 @@ public sealed class OpcUaClientCertAuthTests
|
||||
Should.Throw<FileNotFoundException>(() => OpcUaClientDriver.BuildCertificateIdentity(opts));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that BuildCertificateIdentity loads a valid PFX with private key.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void BuildCertificateIdentity_loads_a_valid_PFX_with_private_key()
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientDiscoveryTests
|
||||
{
|
||||
/// <summary>Verifies that DiscoverAsync throws InvalidOperationException when not initialized.</summary>
|
||||
[Fact]
|
||||
public async Task DiscoverAsync_without_initialize_throws_InvalidOperationException()
|
||||
{
|
||||
@@ -21,6 +22,7 @@ public sealed class OpcUaClientDiscoveryTests
|
||||
await drv.DiscoverAsync(builder, TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that DiscoverAsync rejects null builder argument.</summary>
|
||||
[Fact]
|
||||
public void DiscoverAsync_rejects_null_builder()
|
||||
{
|
||||
@@ -29,6 +31,7 @@ public sealed class OpcUaClientDiscoveryTests
|
||||
await drv.DiscoverAsync(null!, TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that discovery configuration has sensible defaults.</summary>
|
||||
[Fact]
|
||||
public void Discovery_caps_are_sensible_defaults()
|
||||
{
|
||||
@@ -38,17 +41,41 @@ public sealed class OpcUaClientDiscoveryTests
|
||||
opts.BrowseRoot.ShouldBeNull("null = default to ObjectsFolder i=85");
|
||||
}
|
||||
|
||||
/// <summary>Test builder that provides no-op implementations for discovery tests.</summary>
|
||||
private sealed class NullAddressSpaceBuilder : IAddressSpaceBuilder
|
||||
{
|
||||
/// <summary>Returns this builder (no-op).</summary>
|
||||
/// <param name="browseName">The browse name of the folder.</param>
|
||||
/// <param name="displayName">The display name of the folder.</param>
|
||||
public IAddressSpaceBuilder Folder(string browseName, string displayName) => this;
|
||||
|
||||
/// <summary>Returns a stub handle.</summary>
|
||||
/// <param name="browseName">The browse name of the variable.</param>
|
||||
/// <param name="displayName">The display name of the variable.</param>
|
||||
/// <param name="attributeInfo">The attribute information for the variable.</param>
|
||||
public IVariableHandle Variable(string browseName, string displayName, DriverAttributeInfo attributeInfo)
|
||||
=> new StubHandle();
|
||||
|
||||
/// <summary>No-op property addition.</summary>
|
||||
/// <param name="browseName">The browse name of the property.</param>
|
||||
/// <param name="dataType">The data type of the property.</param>
|
||||
/// <param name="value">The property value.</param>
|
||||
public void AddProperty(string browseName, DriverDataType dataType, object? value) { }
|
||||
|
||||
/// <summary>No-op alarm condition attachment.</summary>
|
||||
/// <param name="sourceVariable">The source variable handle.</param>
|
||||
/// <param name="alarmName">The alarm name.</param>
|
||||
/// <param name="alarmInfo">The alarm attribute information.</param>
|
||||
public void AttachAlarmCondition(IVariableHandle sourceVariable, string alarmName, DriverAttributeInfo alarmInfo) { }
|
||||
|
||||
/// <summary>Stub variable handle for testing.</summary>
|
||||
private sealed class StubHandle : IVariableHandle
|
||||
{
|
||||
/// <summary>Gets the full reference as "stub".</summary>
|
||||
public string FullReference => "stub";
|
||||
|
||||
/// <summary>Throws NotSupportedException.</summary>
|
||||
/// <param name="info">The alarm condition information (unused).</param>
|
||||
public IAlarmConditionSink MarkAsAlarmCondition(AlarmConditionInfo info) => throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -12,6 +12,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientDriverScaffoldTests
|
||||
{
|
||||
/// <summary>Verifies that default options target the standard OPC UA port with anonymous auth.</summary>
|
||||
[Fact]
|
||||
public void Default_options_target_standard_opcua_port_and_anonymous_auth()
|
||||
{
|
||||
@@ -23,6 +24,7 @@ public sealed class OpcUaClientDriverScaffoldTests
|
||||
opts.AutoAcceptCertificates.ShouldBeFalse("production default must reject untrusted server certs");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that default timeouts match driver specification section 8.</summary>
|
||||
[Fact]
|
||||
public void Default_timeouts_match_driver_specs_section_8()
|
||||
{
|
||||
@@ -32,6 +34,7 @@ public sealed class OpcUaClientDriverScaffoldTests
|
||||
opts.ReconnectPeriod.ShouldBe(TimeSpan.FromSeconds(5));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that driver reports type and ID before connecting.</summary>
|
||||
[Fact]
|
||||
public void Driver_reports_type_and_id_before_connect()
|
||||
{
|
||||
@@ -41,6 +44,7 @@ public sealed class OpcUaClientDriverScaffoldTests
|
||||
drv.GetHealth().State.ShouldBe(DriverState.Unknown);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that Initialize against unreachable endpoint transitions to Faulted and throws.</summary>
|
||||
[Fact]
|
||||
public async Task Initialize_against_unreachable_endpoint_transitions_to_Faulted_and_throws()
|
||||
{
|
||||
@@ -67,6 +71,7 @@ public sealed class OpcUaClientDriverScaffoldTests
|
||||
health.LastError.ShouldNotBeNull();
|
||||
}
|
||||
|
||||
/// <summary>Verifies that Reinitialize against unreachable endpoint re-throws the error.</summary>
|
||||
[Fact]
|
||||
public async Task Reinitialize_against_unreachable_endpoint_re_throws()
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientFailoverTests
|
||||
{
|
||||
/// <summary>Verifies that ResolveEndpointCandidates prefers EndpointUrls when provided.</summary>
|
||||
[Fact]
|
||||
public void ResolveEndpointCandidates_prefers_EndpointUrls_when_provided()
|
||||
{
|
||||
@@ -21,6 +22,7 @@ public sealed class OpcUaClientFailoverTests
|
||||
list[1].ShouldBe("opc.tcp://backup:4841");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that ResolveEndpointCandidates falls back to single EndpointUrl when list is empty.</summary>
|
||||
[Fact]
|
||||
public void ResolveEndpointCandidates_falls_back_to_single_EndpointUrl_when_list_empty()
|
||||
{
|
||||
@@ -30,6 +32,7 @@ public sealed class OpcUaClientFailoverTests
|
||||
list[0].ShouldBe("opc.tcp://only:4840");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that an empty EndpointUrls list is treated as a fallback to EndpointUrl.</summary>
|
||||
[Fact]
|
||||
public void ResolveEndpointCandidates_empty_list_treated_as_fallback_to_EndpointUrl()
|
||||
{
|
||||
@@ -43,6 +46,7 @@ public sealed class OpcUaClientFailoverTests
|
||||
OpcUaClientDriver.ResolveEndpointCandidates(opts).Count.ShouldBe(1);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that HostName uses the first candidate before connection.</summary>
|
||||
[Fact]
|
||||
public void HostName_uses_first_candidate_before_connect()
|
||||
{
|
||||
@@ -55,6 +59,7 @@ public sealed class OpcUaClientFailoverTests
|
||||
"pre-connect the dashboard should show the first candidate URL so operators can link back");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that initializing against all unreachable endpoints throws AggregateException listing each.</summary>
|
||||
[Fact]
|
||||
public async Task Initialize_against_all_unreachable_endpoints_throws_AggregateException_listing_each()
|
||||
{
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientHistoryTests
|
||||
{
|
||||
/// <summary>Verifies MapAggregateToNodeId returns standard Part 13 aggregate for every enum.</summary>
|
||||
/// <param name="agg">The history aggregate type to test.</param>
|
||||
[Theory]
|
||||
[InlineData(HistoryAggregateType.Average)]
|
||||
[InlineData(HistoryAggregateType.Minimum)]
|
||||
@@ -22,6 +24,7 @@ public sealed class OpcUaClientHistoryTests
|
||||
nodeId.NamespaceIndex.ShouldBe((ushort)0);
|
||||
}
|
||||
|
||||
/// <summary>Verifies MapAggregateToNodeId rejects invalid enum values.</summary>
|
||||
[Fact]
|
||||
public void MapAggregateToNodeId_rejects_invalid_enum_value()
|
||||
{
|
||||
@@ -30,6 +33,7 @@ public sealed class OpcUaClientHistoryTests
|
||||
OpcUaClientDriver.MapAggregateToNodeId((HistoryAggregateType)99));
|
||||
}
|
||||
|
||||
/// <summary>Verifies ReadRawAsync throws without initialization.</summary>
|
||||
[Fact]
|
||||
public async Task ReadRawAsync_without_initialize_throws_InvalidOperationException()
|
||||
{
|
||||
@@ -40,6 +44,7 @@ public sealed class OpcUaClientHistoryTests
|
||||
TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Verifies ReadRawAsync with malformed NodeId returns empty result.</summary>
|
||||
[Fact]
|
||||
public async Task ReadRawAsync_with_malformed_NodeId_returns_empty_result_not_throw()
|
||||
{
|
||||
@@ -52,6 +57,7 @@ public sealed class OpcUaClientHistoryTests
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>Verifies ReadProcessedAsync throws without initialization.</summary>
|
||||
[Fact]
|
||||
public async Task ReadProcessedAsync_without_initialize_throws_InvalidOperationException()
|
||||
{
|
||||
@@ -63,6 +69,7 @@ public sealed class OpcUaClientHistoryTests
|
||||
TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Verifies ReadAtTimeAsync throws without initialization.</summary>
|
||||
[Fact]
|
||||
public async Task ReadAtTimeAsync_without_initialize_throws_InvalidOperationException()
|
||||
{
|
||||
@@ -73,6 +80,7 @@ public sealed class OpcUaClientHistoryTests
|
||||
TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Verifies ReadEventsAsync throws NotSupportedException as documented.</summary>
|
||||
[Fact]
|
||||
public async Task ReadEventsAsync_throws_NotSupportedException_as_documented()
|
||||
{
|
||||
|
||||
+12
@@ -26,6 +26,7 @@ public sealed class OpcUaClientLowFindingsRegressionTests
|
||||
// The decision branches are pure logic; assert them against the SDK constants so a
|
||||
// regression rewriting `valueRank >= 0` shows up in CI.
|
||||
|
||||
/// <summary>Verifies that ValueRank constants match the OPC UA Part 3 specification values.</summary>
|
||||
[Fact]
|
||||
public void ValueRank_constants_have_the_OPCUA_Part3_spec_values()
|
||||
{
|
||||
@@ -39,6 +40,9 @@ public sealed class OpcUaClientLowFindingsRegressionTests
|
||||
ValueRanks.OneDimension.ShouldBe(1);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that IsArray decision matches the valueRank >= 0 boundary.</summary>
|
||||
/// <param name="valueRank">The OPC UA value rank to test.</param>
|
||||
/// <param name="expectedIsArray">Whether the value rank should be treated as an array.</param>
|
||||
[Theory]
|
||||
[InlineData(-3, false)] // ScalarOrOneDimension — conservatively treated as scalar
|
||||
[InlineData(-2, false)] // Any — conservatively treated as scalar
|
||||
@@ -69,6 +73,7 @@ public sealed class OpcUaClientLowFindingsRegressionTests
|
||||
// with the *same delegate instance*. Confirm that further notifications do not
|
||||
// invoke the handler.
|
||||
|
||||
/// <summary>Verifies that RemoteSubscription record carries handler delegates for detachment.</summary>
|
||||
[Fact]
|
||||
public void RemoteSubscription_record_carries_handler_delegates_so_they_can_be_detached()
|
||||
{
|
||||
@@ -95,6 +100,7 @@ public sealed class OpcUaClientLowFindingsRegressionTests
|
||||
"so UnsubscribeAsync/ShutdownAsync can detach the Notification delegate before disposing the session.");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that RemoteAlarmSubscription record carries handler delegate for detachment.</summary>
|
||||
[Fact]
|
||||
public void RemoteAlarmSubscription_record_carries_handler_delegate_so_it_can_be_detached()
|
||||
{
|
||||
@@ -114,6 +120,7 @@ public sealed class OpcUaClientLowFindingsRegressionTests
|
||||
"disposing the session.");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that UnsubscribeAsync with unknown handle does not throw after the fix.</summary>
|
||||
[Fact]
|
||||
public async Task UnsubscribeAsync_unknown_handle_does_not_throw_after_fix()
|
||||
{
|
||||
@@ -124,6 +131,7 @@ public sealed class OpcUaClientLowFindingsRegressionTests
|
||||
await drv.UnsubscribeAsync(new FakeHandle(), TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that UnsubscribeAlarmsAsync with unknown handle does not throw after the fix.</summary>
|
||||
[Fact]
|
||||
public async Task UnsubscribeAlarmsAsync_unknown_handle_does_not_throw_after_fix()
|
||||
{
|
||||
@@ -132,13 +140,17 @@ public sealed class OpcUaClientLowFindingsRegressionTests
|
||||
await drv.UnsubscribeAlarmsAsync(new FakeAlarmHandle(), TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Fake subscription handle for testing.</summary>
|
||||
private sealed class FakeHandle : Core.Abstractions.ISubscriptionHandle
|
||||
{
|
||||
/// <summary>Gets the diagnostic identifier for this handle.</summary>
|
||||
public string DiagnosticId => "fake-sub";
|
||||
}
|
||||
|
||||
/// <summary>Fake alarm subscription handle for testing.</summary>
|
||||
private sealed class FakeAlarmHandle : Core.Abstractions.IAlarmSubscriptionHandle
|
||||
{
|
||||
/// <summary>Gets the diagnostic identifier for this handle.</summary>
|
||||
public string DiagnosticId => "fake-alarm-sub";
|
||||
}
|
||||
}
|
||||
|
||||
+27
@@ -22,6 +22,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
{
|
||||
// ---- Driver.OpcUaClient-009 ----
|
||||
|
||||
/// <summary>Verifies that WriteAsync without session returns BadCommunicationError, not BadTimeout.</summary>
|
||||
[Fact]
|
||||
public async Task WriteAsync_without_session_returns_BadCommunicationError_not_BadTimeout()
|
||||
{
|
||||
@@ -38,6 +39,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
|
||||
// ---- Driver.OpcUaClient-010 ----
|
||||
|
||||
/// <summary>Verifies that Byte data type maps to UInt16, not Int16.</summary>
|
||||
[Fact]
|
||||
public void MapUpstreamDataType_Byte_maps_to_UInt16_unsigned_family()
|
||||
{
|
||||
@@ -47,6 +49,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
result.ShouldNotBe(DriverDataType.Int16, "Byte is unsigned; Int16 is signed — wrong family");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that SByte data type maps to Int16 signed family.</summary>
|
||||
[Fact]
|
||||
public void MapUpstreamDataType_SByte_still_maps_to_Int16_signed_family()
|
||||
{
|
||||
@@ -57,6 +60,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
|
||||
// ---- Driver.OpcUaClient-012 ----
|
||||
|
||||
/// <summary>Verifies that AutoAcceptCertificates defaults to false.</summary>
|
||||
[Fact]
|
||||
public void AutoAcceptCertificates_default_is_false_secure_by_default()
|
||||
{
|
||||
@@ -64,6 +68,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
"production default must reject untrusted server certs to prevent MITM");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that InitializeAsync with AutoAccept emits a warning log.</summary>
|
||||
[Fact]
|
||||
public async Task InitializeAsync_AutoAccept_emits_warning_log()
|
||||
{
|
||||
@@ -93,6 +98,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
|
||||
// ---- Driver.OpcUaClient-013 ----
|
||||
|
||||
/// <summary>Verifies that GetMemoryFootprint returns zero before discovery.</summary>
|
||||
[Fact]
|
||||
public void GetMemoryFootprint_returns_zero_before_first_discovery()
|
||||
{
|
||||
@@ -101,6 +107,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
drv.GetMemoryFootprint().ShouldBe(0L);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that FlushOptionalCachesAsync completes without throwing.</summary>
|
||||
[Fact]
|
||||
public async Task FlushOptionalCachesAsync_completes_without_throwing()
|
||||
{
|
||||
@@ -110,6 +117,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
await drv.FlushOptionalCachesAsync(TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that FlushOptionalCachesAsync resets the footprint counter.</summary>
|
||||
[Fact]
|
||||
public async Task FlushOptionalCachesAsync_resets_footprint_counter()
|
||||
{
|
||||
@@ -125,6 +133,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
|
||||
// ---- Driver.OpcUaClient-015: pure-logic paths ----
|
||||
|
||||
/// <summary>Verifies that MapSeverity thresholds match OPC UA AC Part 9 guidance.</summary>
|
||||
[Fact]
|
||||
public void MapSeverity_thresholds_match_opcua_ac_part9_guidance()
|
||||
{
|
||||
@@ -139,6 +148,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
OpcUaClientDriver.MapSeverity(1000).ShouldBe(AlarmSeverity.Critical);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that driver health starts Unknown and is accessible before init.</summary>
|
||||
[Fact]
|
||||
public void Driver_health_starts_Unknown_and_is_accessible_before_init()
|
||||
{
|
||||
@@ -151,6 +161,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
h.LastSuccessfulRead.ShouldBeNull();
|
||||
}
|
||||
|
||||
/// <summary>Verifies that driver Session is null before init and RequireSession throws.</summary>
|
||||
[Fact]
|
||||
public void Driver_Session_is_null_before_init_so_RequireSession_throws()
|
||||
{
|
||||
@@ -160,6 +171,7 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
drv.Session.ShouldBeNull();
|
||||
}
|
||||
|
||||
/// <summary>Verifies that GetHostStatuses returns single entry keyed to configured endpoint.</summary>
|
||||
[Fact]
|
||||
public void GetHostStatuses_returns_single_entry_keyed_to_configured_endpoint()
|
||||
{
|
||||
@@ -177,11 +189,26 @@ public sealed class OpcUaClientMediumFindingsRegressionTests
|
||||
|
||||
private sealed class CapturingLogger : ILogger<OpcUaClientDriver>
|
||||
{
|
||||
/// <summary>Gets the captured log entries.</summary>
|
||||
public List<(LogLevel Level, string Message)> Entries { get; } = [];
|
||||
|
||||
/// <summary>Begins a logical scope.</summary>
|
||||
/// <typeparam name="TState">The type of the state object.</typeparam>
|
||||
/// <param name="state">The state to scope.</param>
|
||||
/// <returns>An IDisposable representing the scope.</returns>
|
||||
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => null;
|
||||
/// <summary>Checks if logging is enabled for the specified level.</summary>
|
||||
/// <param name="logLevel">The log level.</param>
|
||||
/// <returns>True if logging is enabled.</returns>
|
||||
public bool IsEnabled(LogLevel logLevel) => true;
|
||||
|
||||
/// <summary>Logs a message.</summary>
|
||||
/// <typeparam name="TState">The type of the state object.</typeparam>
|
||||
/// <param name="logLevel">The log level.</param>
|
||||
/// <param name="eventId">The event ID.</param>
|
||||
/// <param name="state">The state.</param>
|
||||
/// <param name="exception">The exception.</param>
|
||||
/// <param name="formatter">The formatter function.</param>
|
||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
|
||||
Exception? exception, Func<TState, Exception?, string> formatter)
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@ public sealed class OpcUaClientNamespaceTests
|
||||
{
|
||||
// ---- Driver.OpcUaClient-004: TargetNamespaceKind startup enforcement ----
|
||||
|
||||
/// <summary>Verifies that Equipment namespace kind without mapping table is rejected.</summary>
|
||||
[Fact]
|
||||
public void ValidateNamespaceKind_Equipment_without_mapping_table_is_rejected()
|
||||
{
|
||||
@@ -24,6 +25,7 @@ public sealed class OpcUaClientNamespaceTests
|
||||
.Message.ShouldContain("UnsMappingTable");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that Equipment namespace kind with mapping table passes.</summary>
|
||||
[Fact]
|
||||
public void ValidateNamespaceKind_Equipment_with_mapping_table_passes()
|
||||
{
|
||||
@@ -35,6 +37,7 @@ public sealed class OpcUaClientNamespaceTests
|
||||
Should.NotThrow(() => OpcUaClientDriver.ValidateNamespaceKind(opts));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that SystemPlatform namespace kind with mapping table is rejected.</summary>
|
||||
[Fact]
|
||||
public void ValidateNamespaceKind_SystemPlatform_with_mapping_table_is_rejected()
|
||||
{
|
||||
@@ -48,6 +51,7 @@ public sealed class OpcUaClientNamespaceTests
|
||||
.Message.ShouldContain("SystemPlatform");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that SystemPlatform namespace kind without mapping table passes.</summary>
|
||||
[Fact]
|
||||
public void ValidateNamespaceKind_SystemPlatform_without_mapping_table_passes()
|
||||
{
|
||||
@@ -55,6 +59,7 @@ public sealed class OpcUaClientNamespaceTests
|
||||
Should.NotThrow(() => OpcUaClientDriver.ValidateNamespaceKind(opts));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that the default target namespace kind is Equipment.</summary>
|
||||
[Fact]
|
||||
public void Default_TargetNamespaceKind_is_Equipment()
|
||||
{
|
||||
@@ -64,10 +69,12 @@ public sealed class OpcUaClientNamespaceTests
|
||||
|
||||
// ---- Driver.OpcUaClient-004: server-stable NodeId encoding ----
|
||||
|
||||
/// <summary>Verifies that NamespaceMap.FromSession rejects null session.</summary>
|
||||
[Fact]
|
||||
public void NamespaceMap_FromSession_rejects_null_session() =>
|
||||
Should.Throw<ArgumentNullException>(() => NamespaceMap.FromSession(null!));
|
||||
|
||||
/// <summary>Verifies that namespace 0 NodeId keeps compact form.</summary>
|
||||
[Fact]
|
||||
public void NamespaceMap_namespace0_NodeId_keeps_compact_form()
|
||||
{
|
||||
@@ -79,6 +86,7 @@ public sealed class OpcUaClientNamespaceTests
|
||||
map.ToStableReference(coreNode).ShouldNotContain("nsu=");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that nonzero namespace NodeId is encoded with URI, not index.</summary>
|
||||
[Fact]
|
||||
public void NamespaceMap_nonzero_namespace_NodeId_is_encoded_with_uri_not_index()
|
||||
{
|
||||
@@ -92,6 +100,7 @@ public sealed class OpcUaClientNamespaceTests
|
||||
stable.ShouldNotStartWith("ns=1");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that unknown namespace index falls back to raw form.</summary>
|
||||
[Fact]
|
||||
public void NamespaceMap_unknown_namespace_index_falls_back_to_raw_form()
|
||||
{
|
||||
@@ -102,6 +111,7 @@ public sealed class OpcUaClientNamespaceTests
|
||||
Should.NotThrow(() => map.ToStableReference(node));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that namespace index and URI lookups are bidirectional.</summary>
|
||||
[Fact]
|
||||
public void NamespaceMap_index_and_uri_lookups_are_bidirectional()
|
||||
{
|
||||
@@ -113,6 +123,7 @@ public sealed class OpcUaClientNamespaceTests
|
||||
map.UriForIndex(99).ShouldBeNull();
|
||||
}
|
||||
|
||||
/// <summary>Verifies that NamespaceMap.TryResolve rejects empty and null input.</summary>
|
||||
[Fact]
|
||||
public void NamespaceMap_TryResolve_rejects_empty_and_null_input()
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientReadWriteTests
|
||||
{
|
||||
/// <summary>Verifies that ReadAsync throws InvalidOperationException when not initialized.</summary>
|
||||
[Fact]
|
||||
public async Task ReadAsync_without_initialize_throws_InvalidOperationException()
|
||||
{
|
||||
@@ -20,6 +21,7 @@ public sealed class OpcUaClientReadWriteTests
|
||||
await drv.ReadAsync(["ns=2;s=Demo"], TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that WriteAsync throws InvalidOperationException when not initialized.</summary>
|
||||
[Fact]
|
||||
public async Task WriteAsync_without_initialize_throws_InvalidOperationException()
|
||||
{
|
||||
|
||||
@@ -11,12 +11,14 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientReconnectTests
|
||||
{
|
||||
/// <summary>Verifies that the default reconnect period matches the driver specification of 5 seconds.</summary>
|
||||
[Fact]
|
||||
public void Default_ReconnectPeriod_matches_driver_specs_5_seconds()
|
||||
{
|
||||
new OpcUaClientDriverOptions().ReconnectPeriod.ShouldBe(TimeSpan.FromSeconds(5));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that reconnect period can be configured for aggressive or relaxed retries.</summary>
|
||||
[Fact]
|
||||
public void Options_ReconnectPeriod_is_configurable_for_aggressive_or_relaxed_retry()
|
||||
{
|
||||
@@ -24,6 +26,7 @@ public sealed class OpcUaClientReconnectTests
|
||||
opts.ReconnectPeriod.ShouldBe(TimeSpan.FromMilliseconds(500));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that the driver starts with no reconnect handler active before initialization.</summary>
|
||||
[Fact]
|
||||
public void Driver_starts_with_no_reconnect_handler_active_pre_init()
|
||||
{
|
||||
|
||||
+6
@@ -7,6 +7,8 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientSecurityPolicyTests
|
||||
{
|
||||
/// <summary>Verifies that every security policy enum value maps to a known non-empty URI.</summary>
|
||||
/// <param name="policy">The OPC UA security policy to map.</param>
|
||||
[Theory]
|
||||
[InlineData(OpcUaSecurityPolicy.None)]
|
||||
[InlineData(OpcUaSecurityPolicy.Basic128Rsa15)]
|
||||
@@ -24,6 +26,7 @@ public sealed class OpcUaClientSecurityPolicyTests
|
||||
uri.ShouldContain(policy.ToString());
|
||||
}
|
||||
|
||||
/// <summary>Verifies that None security policy maps to the SDK None URI.</summary>
|
||||
[Fact]
|
||||
public void MapSecurityPolicy_None_matches_SDK_None_URI()
|
||||
{
|
||||
@@ -31,6 +34,7 @@ public sealed class OpcUaClientSecurityPolicyTests
|
||||
.ShouldBe(SecurityPolicies.None);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that Basic256Sha256 policy maps to the SDK URI.</summary>
|
||||
[Fact]
|
||||
public void MapSecurityPolicy_Basic256Sha256_matches_SDK_URI()
|
||||
{
|
||||
@@ -38,6 +42,7 @@ public sealed class OpcUaClientSecurityPolicyTests
|
||||
.ShouldBe(SecurityPolicies.Basic256Sha256);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that Aes256_Sha256_RsaPss policy maps to the SDK URI.</summary>
|
||||
[Fact]
|
||||
public void MapSecurityPolicy_Aes256_Sha256_RsaPss_matches_SDK_URI()
|
||||
{
|
||||
@@ -45,6 +50,7 @@ public sealed class OpcUaClientSecurityPolicyTests
|
||||
.ShouldBe(SecurityPolicies.Aes256_Sha256_RsaPss);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that every security policy enum value has a mapping.</summary>
|
||||
[Fact]
|
||||
public void Every_enum_value_has_a_mapping()
|
||||
{
|
||||
|
||||
+5
@@ -13,6 +13,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.OpcUaClient.Tests;
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class OpcUaClientSubscribeAndProbeTests
|
||||
{
|
||||
/// <summary>Verifies that subscribe without initialization throws InvalidOperationException.</summary>
|
||||
[Fact]
|
||||
public async Task SubscribeAsync_without_initialize_throws_InvalidOperationException()
|
||||
{
|
||||
@@ -21,6 +22,7 @@ public sealed class OpcUaClientSubscribeAndProbeTests
|
||||
await drv.SubscribeAsync(["ns=2;s=Demo"], TimeSpan.FromMilliseconds(100), TestContext.Current.CancellationToken));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that unsubscribe with unknown handle is a no-op.</summary>
|
||||
[Fact]
|
||||
public async Task UnsubscribeAsync_with_unknown_handle_is_noop()
|
||||
{
|
||||
@@ -30,6 +32,7 @@ public sealed class OpcUaClientSubscribeAndProbeTests
|
||||
await drv.UnsubscribeAsync(new FakeHandle(), TestContext.Current.CancellationToken);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that GetHostStatuses returns endpoint URL row before initialization.</summary>
|
||||
[Fact]
|
||||
public void GetHostStatuses_returns_endpoint_url_row_pre_init()
|
||||
{
|
||||
@@ -43,8 +46,10 @@ public sealed class OpcUaClientSubscribeAndProbeTests
|
||||
rows[0].State.ShouldBe(HostState.Unknown);
|
||||
}
|
||||
|
||||
/// <summary>A fake subscription handle for testing.</summary>
|
||||
private sealed class FakeHandle : ISubscriptionHandle
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string DiagnosticId => "fake";
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user