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
@@ -18,6 +18,9 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests;
public sealed class AddressingGrammarTests
{
private readonly ModbusSimulatorFixture _sim;
/// <summary>Initializes a new instance of the AddressingGrammarTests class.</summary>
/// <param name="sim">The Modbus simulator fixture.</param>
public AddressingGrammarTests(ModbusSimulatorFixture sim) => _sim = sim;
private async Task<ModbusDriver> NewDriverAsync(params ModbusTagDefinition[] tags)
@@ -32,6 +35,7 @@ public sealed class AddressingGrammarTests
return drv;
}
/// <summary>Verifies that 5-digit and 6-digit Modicon formats map to the same wire offset.</summary>
[Fact]
public async Task Modicon_5_And_6_Digit_Both_Map_To_Same_Wire_Offset()
{
@@ -49,6 +53,7 @@ public sealed class AddressingGrammarTests
await drv.ShutdownAsync(CancellationToken.None);
}
/// <summary>Verifies that Float32 values roundtrip correctly with CDAB byte order.</summary>
[Fact]
public async Task Float32_With_CDAB_Roundtrips_Through_Wire()
{
@@ -70,6 +75,7 @@ public sealed class AddressingGrammarTests
await drv.ShutdownAsync(CancellationToken.None);
}
/// <summary>Verifies that Int16 array reads surface as typed arrays.</summary>
[Fact]
public async Task Int16_Array_Reads_Surface_As_Typed_Array()
{
@@ -86,6 +92,7 @@ public sealed class AddressingGrammarTests
await drv.ShutdownAsync(CancellationToken.None);
}
/// <summary>Verifies that block read coalescing reduces PDU count end-to-end.</summary>
[Fact]
public async Task Block_Read_Coalescing_Reduces_PDU_Count_End_To_End()
{
@@ -14,6 +14,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.DL205;
[Trait("Device", "DL205")]
public sealed class DL205BcdQuirkTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies DL205 binary-coded-decimal register decodes as decimal value 1234.</summary>
[Fact]
public async Task DL205_BCD16_decodes_HR1072_as_decimal_1234()
{
@@ -14,6 +14,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.DL205;
[Trait("Device", "DL205")]
public sealed class DL205CoilMappingTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies that DirectLOGIC Y0 output maps to Modbus coil 2048.</summary>
[Fact]
public async Task DL260_Y0_maps_to_coil_2048()
{
@@ -40,6 +41,7 @@ public sealed class DL205CoilMappingTests(ModbusSimulatorFixture sim)
results[0].Value.ShouldBe(true, "dl205.json seeds coil 2048 (Y0) = ON");
}
/// <summary>Verifies that DirectLOGIC C0 relay maps to Modbus coil 3072.</summary>
[Fact]
public async Task DL260_C0_maps_to_coil_3072()
{
@@ -66,6 +68,7 @@ public sealed class DL205CoilMappingTests(ModbusSimulatorFixture sim)
results[0].Value.ShouldBe(true, "dl205.json seeds coil 3072 (C0) = ON");
}
/// <summary>Verifies that a scratch DirectLOGIC C relay supports write and read operations.</summary>
[Fact]
public async Task DL260_scratch_Crelay_supports_write_then_read()
{
@@ -16,6 +16,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.DL205;
[Trait("Device", "DL205")]
public sealed class DL205ExceptionCodeTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies that DL205 FC03 reads at unmapped registers return BadOutOfRange status.</summary>
[Fact]
public async Task DL205_FC03_at_unmapped_register_returns_BadOutOfRange()
{
@@ -16,6 +16,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.DL205;
[Trait("Device", "DL205")]
public sealed class DL205FloatCdabQuirkTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies that DL205 float32 CDAB word order correctly decodes 1.5f from HR1056.</summary>
[Fact]
public async Task DL205_Float32_CDAB_decodes_1_5f_from_HR1056()
{
@@ -27,6 +27,10 @@ public static class DL205Profile
/// <summary>Value the smoke test writes then reads back to assert round-trip integrity.</summary>
public const short SmokeHoldingValue = 1234;
/// <summary>Builds Modbus driver options for the DL205 test profile.</summary>
/// <param name="host">The host or IP address of the Modbus device.</param>
/// <param name="port">The port number of the Modbus device.</param>
/// <returns>Configured Modbus driver options for DL205.</returns>
public static ModbusDriverOptions BuildOptions(string host, int port) => new()
{
Host = host,
@@ -25,6 +25,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.DL205;
[Trait("Device", "DL205")]
public sealed class DL205SmokeTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies that DL205 roundtrip write then read of holding register succeeds.</summary>
[Fact]
public async Task DL205_roundtrip_write_then_read_of_holding_register()
{
@@ -23,6 +23,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.DL205;
[Trait("Device", "DL205")]
public sealed class DL205StringQuirkTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies that DL205 low-byte-first string packing correctly decodes "Hello" from HR1040.</summary>
[Fact]
public async Task DL205_string_low_byte_first_decodes_Hello_from_HR1040()
{
@@ -16,6 +16,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.DL205;
[Trait("Device", "DL205")]
public sealed class DL205VMemoryQuirkTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies that DL205 V2000 user memory octal address resolves to PDU address 0x0400.</summary>
[Fact]
public async Task DL205_V2000_user_memory_resolves_to_PDU_0x0400_marker()
{
@@ -51,6 +52,7 @@ public sealed class DL205VMemoryQuirkTests(ModbusSimulatorFixture sim)
results[0].Value.ShouldBe((ushort)0x2000, "dl205.json seeds HR[0x0400] with marker 0x2000 (= V2000 value)");
}
/// <summary>Verifies that DL205 V40400 system memory address resolves to PDU address 0x2100.</summary>
[Fact]
public async Task DL205_V40400_system_memory_resolves_to_PDU_0x2100_marker()
{
@@ -21,6 +21,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.DL205;
[Trait("Device", "DL205")]
public sealed class DL205XInputTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies that DL260 X20 octal maps to discrete input 16 and reads the ON state.</summary>
[Fact]
public async Task DL260_X20_octal_maps_to_DiscreteInput_16_and_reads_ON()
{
@@ -60,6 +60,10 @@ public sealed class ExceptionInjectionTests(ModbusSimulatorFixture sim)
return await driver.ReadAsync([tagName], TestContext.Current.CancellationToken);
}
/// <summary>Verifies that Modbus FC03 reads at injected exception addresses surface the expected OPC UA status codes.</summary>
/// <param name="address">The Modbus register address to read.</param>
/// <param name="expectedStatus">The expected OPC UA status code.</param>
/// <param name="scenario">Scenario description for assertion messages.</param>
[Theory]
[InlineData(1000, StatusBadNotSupported, "exc 0x01 (Illegal Function) -> BadNotSupported")]
[InlineData(1001, StatusBadOutOfRange, "exc 0x02 (Illegal Data Address) -> BadOutOfRange")]
@@ -77,6 +81,7 @@ public sealed class ExceptionInjectionTests(ModbusSimulatorFixture sim)
results[0].StatusCode.ShouldBe(expectedStatus, scenario);
}
/// <summary>Verifies that reads at non-injected addresses return Good status.</summary>
[Fact]
public async Task FC03_read_at_non_injected_address_returns_Good()
{
@@ -89,6 +94,10 @@ public sealed class ExceptionInjectionTests(ModbusSimulatorFixture sim)
results[0].Value.ShouldBe((ushort)5);
}
/// <summary>Verifies that Modbus FC06 writes at injected exception addresses surface the expected OPC UA status codes.</summary>
/// <param name="address">The Modbus register address to write.</param>
/// <param name="expectedStatus">The expected OPC UA status code.</param>
/// <param name="scenario">Scenario description for assertion messages.</param>
[Theory]
[InlineData(2000, StatusBadDeviceFailure, "exc 0x04 on FC06 -> BadDeviceFailure (CPU in PROGRAM mode)")]
[InlineData(2001, StatusBadDeviceFailure, "exc 0x06 on FC06 -> BadDeviceFailure (Server Busy)")]
@@ -23,6 +23,9 @@ public static class MitsubishiProfile
/// <summary>Value the smoke test writes then reads back.</summary>
public const short SmokeHoldingValue = 7890;
/// <summary>Builds Modbus driver options configured for the Mitsubishi profile.</summary>
/// <param name="host">The Modbus server hostname or IP address.</param>
/// <param name="port">The Modbus server port number.</param>
public static ModbusDriverOptions BuildOptions(string host, int port) => new()
{
Host = host,
@@ -19,6 +19,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.Mitsubishi;
[Trait("Device", "Mitsubishi")]
public sealed class MitsubishiQuirkTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies that Mitsubishi D0 register fingerprint reads the expected value 0x1234.</summary>
[Fact]
public async Task Mitsubishi_D0_fingerprint_reads_0x1234()
{
@@ -34,6 +35,7 @@ public sealed class MitsubishiQuirkTests(ModbusSimulatorFixture sim)
r[0].Value.ShouldBe((ushort)0x1234);
}
/// <summary>Verifies that Mitsubishi Float32 with CDAB word order decodes correctly to 1.5 from D100.</summary>
[Fact]
public async Task Mitsubishi_Float32_CDAB_decodes_1_5f_from_D100()
{
@@ -59,6 +61,7 @@ public sealed class MitsubishiQuirkTests(ModbusSimulatorFixture sim)
r[1].Value.ShouldNotBe(1.5f, "same wire with BigEndian must decode to a different value");
}
/// <summary>Verifies that Mitsubishi D registers store binary values, not BCD.</summary>
[Fact]
public async Task Mitsubishi_D10_is_binary_not_BCD()
{
@@ -77,6 +80,7 @@ public sealed class MitsubishiQuirkTests(ModbusSimulatorFixture sim)
r[0].Value.ShouldBe((short)1234, "MELSEC stores numeric D-register values in binary; 0x04D2 = 1234");
}
/// <summary>Verifies that reading a binary D register as BCD throws when the value contains non-decimal nibbles.</summary>
[Fact]
public async Task Mitsubishi_D10_as_BCD_throws_because_nibble_is_non_decimal()
{
@@ -97,6 +101,7 @@ public sealed class MitsubishiQuirkTests(ModbusSimulatorFixture sim)
r[0].StatusCode.ShouldNotBe(0u, "BCD decode of binary 0x04D2 must fail loudly because nibble D is non-BCD");
}
/// <summary>Verifies that Mitsubishi Q/L/iQ-R X inputs use hex addressing and X210 maps correctly.</summary>
[Fact]
public async Task Mitsubishi_QLiQR_X210_hex_maps_to_DI_528_reads_ON()
{
@@ -117,6 +122,7 @@ public sealed class MitsubishiQuirkTests(ModbusSimulatorFixture sim)
r[0].Value.ShouldBe(true);
}
/// <summary>Verifies that X input address mapping differs between Mitsubishi MELSEC families (Q vs FX).</summary>
[Fact]
public void Mitsubishi_family_trap_X20_differs_on_Q_vs_FX()
{
@@ -127,6 +133,7 @@ public sealed class MitsubishiQuirkTests(ModbusSimulatorFixture sim)
MelsecAddress.XInputToDiscrete("X20", MelsecFamily.F_iQF).ShouldBe((ushort)16);
}
/// <summary>Verifies that Mitsubishi M512 relay maps to coil address 512 and reads ON.</summary>
[Fact]
public async Task Mitsubishi_M512_maps_to_coil_512_reads_ON()
{
@@ -15,6 +15,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.Mitsubishi;
[Trait("Device", "Mitsubishi")]
public sealed class MitsubishiSmokeTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies end-to-end write and read of a Mitsubishi holding register via the Modbus driver.</summary>
[Fact]
public async Task Mitsubishi_roundtrip_write_then_read_of_holding_register()
{
@@ -36,10 +36,16 @@ public sealed class ModbusSimulatorFixture : IAsyncDisposable
private const string DefaultEndpoint = "10.100.0.35:5020";
private const string EndpointEnvVar = "MODBUS_SIM_ENDPOINT";
/// <summary>Gets the host address of the Modbus simulator.</summary>
public string Host { get; }
/// <summary>Gets the port of the Modbus simulator.</summary>
public int Port { get; }
/// <summary>Gets the skip reason if the simulator is unreachable; otherwise null.</summary>
public string? SkipReason { get; }
/// <summary>Initializes a new instance of the <see cref="ModbusSimulatorFixture"/> class.</summary>
public ModbusSimulatorFixture()
{
var raw = Environment.GetEnvironmentVariable(EndpointEnvVar) ?? DefaultEndpoint;
@@ -76,6 +82,7 @@ public sealed class ModbusSimulatorFixture : IAsyncDisposable
}
}
/// <inheritdoc />
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
}
@@ -22,6 +22,10 @@ public static class S7_1500Profile
/// <summary>Value the smoke test writes then reads back.</summary>
public const short SmokeHoldingValue = 4321;
/// <summary>Builds Modbus driver options for the S7-1500 profile.</summary>
/// <param name="host">The host address of the Modbus device.</param>
/// <param name="port">The port number of the Modbus device.</param>
/// <returns>The configured Modbus driver options.</returns>
public static ModbusDriverOptions BuildOptions(string host, int port) => new()
{
Host = host,
@@ -24,6 +24,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.S7;
[Trait("Device", "S7")]
public sealed class S7_1500SmokeTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies that an S7-1500 roundtrip write then read of a holding register succeeds.</summary>
[Fact]
public async Task S7_1500_roundtrip_write_then_read_of_holding_register()
{
@@ -16,6 +16,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Modbus.IntegrationTests.S7;
[Trait("Device", "S7")]
public sealed class S7_ByteOrderTests(ModbusSimulatorFixture sim)
{
/// <summary>Verifies that S7 Float32 with ABCD byte order correctly decodes 1.5f from HR100.</summary>
[Fact]
public async Task S7_Float32_ABCD_decodes_1_5f_from_HR100()
{
@@ -61,6 +62,7 @@ public sealed class S7_ByteOrderTests(ModbusSimulatorFixture sim)
results[1].Value.ShouldNotBe(1.5f, "applying CDAB swap to S7 ABCD bytes must produce a different value — confirms the flag is not a no-op and S7 profile default must be BigEndian");
}
/// <summary>Verifies that S7 Int32 with ABCD byte order correctly decodes 0x12345678 from HR300.</summary>
[Fact]
public async Task S7_Int32_ABCD_decodes_0x12345678_from_HR300()
{
@@ -95,6 +97,7 @@ public sealed class S7_ByteOrderTests(ModbusSimulatorFixture sim)
"S7 Int32 stored as HR[300]=0x1234, HR[301]=0x5678 with ABCD order decodes to 0x12345678 — DL260 would store the reverse order");
}
/// <summary>Verifies that S7 DB1 fingerprint marker reads 0xABCD from HR0.</summary>
[Fact]
public async Task S7_DB1_fingerprint_marker_at_HR0_reads_0xABCD()
{