docs: complete XML doc comments via fixdocs (2757 to 131 findings)
Add missing <returns>/<param>/<summary>/<typeparam> tags and clean up misused inheritdoc across 481 files so the documented API surface is complete. Documentation-only (zero code lines changed). The 131 remaining findings are inheritdoc-style warnings deliberately left to preserve hand-written implementation rationale (plan-decision notes, race-condition explanations).
This commit is contained in:
@@ -4,7 +4,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests;
|
||||
|
||||
internal class FakeFocasClient : IFocasClient
|
||||
{
|
||||
/// <summary>Gets a value indicating whether the client is connected.</summary>
|
||||
/// <inheritdoc />
|
||||
public bool IsConnected { get; private set; }
|
||||
/// <summary>Gets the count of connection attempts.</summary>
|
||||
public int ConnectCount { get; private set; }
|
||||
@@ -30,10 +30,7 @@ internal class FakeFocasClient : IFocasClient
|
||||
/// <summary>Gets the log of write operations.</summary>
|
||||
public List<(FocasAddress addr, FocasDataType type, object? value)> WriteLog { get; } = new();
|
||||
|
||||
/// <summary>Connects to a FOCAS host asynchronously.</summary>
|
||||
/// <param name="address">The FOCAS host address.</param>
|
||||
/// <param name="timeout">The connection timeout duration.</param>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task ConnectAsync(FocasHostAddress address, TimeSpan timeout, CancellationToken ct)
|
||||
{
|
||||
ConnectCount++;
|
||||
@@ -42,10 +39,7 @@ internal class FakeFocasClient : IFocasClient
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>Reads a value from a FOCAS address asynchronously.</summary>
|
||||
/// <param name="address">The FOCAS address to read from.</param>
|
||||
/// <param name="type">The data type of the value.</param>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<(object? value, uint status)> ReadAsync(
|
||||
FocasAddress address, FocasDataType type, CancellationToken ct)
|
||||
{
|
||||
@@ -56,11 +50,7 @@ internal class FakeFocasClient : IFocasClient
|
||||
return Task.FromResult((value, status));
|
||||
}
|
||||
|
||||
/// <summary>Writes a value to a FOCAS address asynchronously.</summary>
|
||||
/// <param name="address">The FOCAS address to write to.</param>
|
||||
/// <param name="type">The data type of the value.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<uint> WriteAsync(
|
||||
FocasAddress address, FocasDataType type, object? value, CancellationToken ct)
|
||||
{
|
||||
@@ -71,15 +61,13 @@ internal class FakeFocasClient : IFocasClient
|
||||
return Task.FromResult(status);
|
||||
}
|
||||
|
||||
/// <summary>Probes the FOCAS connection asynchronously.</summary>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<bool> ProbeAsync(CancellationToken ct) => Task.FromResult(ProbeResult);
|
||||
|
||||
/// <summary>Gets the list of active alarms.</summary>
|
||||
public List<FocasActiveAlarm> Alarms { get; } = [];
|
||||
|
||||
/// <summary>Reads active alarms asynchronously.</summary>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<IReadOnlyList<FocasActiveAlarm>> ReadAlarmsAsync(CancellationToken ct) =>
|
||||
Task.FromResult<IReadOnlyList<FocasActiveAlarm>>([.. Alarms]);
|
||||
|
||||
@@ -93,20 +81,15 @@ internal class FakeFocasClient : IFocasClient
|
||||
/// <summary>Gets the dictionary of dynamic snapshots keyed by axis index.</summary>
|
||||
public Dictionary<int, FocasDynamicSnapshot> DynamicByAxis { get; } = [];
|
||||
|
||||
/// <summary>Gets system information asynchronously.</summary>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<FocasSysInfo> GetSysInfoAsync(CancellationToken ct) => Task.FromResult(SysInfo);
|
||||
/// <summary>Gets axis names asynchronously.</summary>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<IReadOnlyList<FocasAxisName>> GetAxisNamesAsync(CancellationToken ct) =>
|
||||
Task.FromResult<IReadOnlyList<FocasAxisName>>([.. AxisNames]);
|
||||
/// <summary>Gets spindle names asynchronously.</summary>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<IReadOnlyList<FocasSpindleName>> GetSpindleNamesAsync(CancellationToken ct) =>
|
||||
Task.FromResult<IReadOnlyList<FocasSpindleName>>([.. SpindleNames]);
|
||||
/// <summary>Reads dynamic data for an axis asynchronously.</summary>
|
||||
/// <param name="axisIndex">The zero-based axis index.</param>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<FocasDynamicSnapshot> ReadDynamicAsync(int axisIndex, CancellationToken ct)
|
||||
{
|
||||
if (!DynamicByAxis.TryGetValue(axisIndex, out var snap))
|
||||
@@ -116,16 +99,13 @@ internal class FakeFocasClient : IFocasClient
|
||||
|
||||
/// <summary>Gets or sets the program information.</summary>
|
||||
public FocasProgramInfo ProgramInfo { get; set; } = new("O0001", 1, 0, 1);
|
||||
/// <summary>Gets program information asynchronously.</summary>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<FocasProgramInfo> GetProgramInfoAsync(CancellationToken ct) =>
|
||||
Task.FromResult(ProgramInfo);
|
||||
|
||||
/// <summary>Gets the dictionary of timers keyed by timer kind.</summary>
|
||||
public Dictionary<FocasTimerKind, FocasTimer> Timers { get; } = [];
|
||||
/// <summary>Gets timer data asynchronously.</summary>
|
||||
/// <param name="kind">The timer kind to retrieve.</param>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<FocasTimer> GetTimerAsync(FocasTimerKind kind, CancellationToken ct)
|
||||
{
|
||||
if (!Timers.TryGetValue(kind, out var t))
|
||||
@@ -135,8 +115,7 @@ internal class FakeFocasClient : IFocasClient
|
||||
|
||||
/// <summary>Gets the list of servo loads.</summary>
|
||||
public List<FocasServoLoad> ServoLoads { get; } = [];
|
||||
/// <summary>Gets servo loads asynchronously.</summary>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<IReadOnlyList<FocasServoLoad>> GetServoLoadsAsync(CancellationToken ct) =>
|
||||
Task.FromResult<IReadOnlyList<FocasServoLoad>>([.. ServoLoads]);
|
||||
|
||||
@@ -144,12 +123,10 @@ internal class FakeFocasClient : IFocasClient
|
||||
public List<int> SpindleLoads { get; } = [];
|
||||
/// <summary>Gets the list of spindle maximum RPMs.</summary>
|
||||
public List<int> SpindleMaxRpms { get; } = [];
|
||||
/// <summary>Gets spindle loads asynchronously.</summary>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<IReadOnlyList<int>> GetSpindleLoadsAsync(CancellationToken ct) =>
|
||||
Task.FromResult<IReadOnlyList<int>>([.. SpindleLoads]);
|
||||
/// <summary>Gets spindle maximum RPMs asynchronously.</summary>
|
||||
/// <param name="ct">The cancellation token.</param>
|
||||
/// <inheritdoc />
|
||||
public virtual Task<IReadOnlyList<int>> GetSpindleMaxRpmsAsync(CancellationToken ct) =>
|
||||
Task.FromResult<IReadOnlyList<int>>([.. SpindleMaxRpms]);
|
||||
|
||||
@@ -169,7 +146,7 @@ internal sealed class FakeFocasClientFactory : IFocasClientFactory
|
||||
/// <summary>Gets or sets a customization function for creating clients.</summary>
|
||||
public Func<FakeFocasClient>? Customise { get; set; }
|
||||
|
||||
/// <summary>Creates a fake FOCAS client.</summary>
|
||||
/// <inheritdoc />
|
||||
public IFocasClient Create()
|
||||
{
|
||||
var c = Customise?.Invoke() ?? new FakeFocasClient();
|
||||
|
||||
@@ -27,6 +27,7 @@ public sealed class FocasAlarmProjectionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that subscribe without enable throws NotSupported.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Subscribe_without_Enable_throws_NotSupported()
|
||||
{
|
||||
@@ -38,6 +39,7 @@ public sealed class FocasAlarmProjectionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that raise then clear emits both events.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Raise_then_clear_emits_both_events()
|
||||
{
|
||||
@@ -70,6 +72,7 @@ public sealed class FocasAlarmProjectionTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that tick diffs raises and clears without polling loop.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Tick_diffs_raises_and_clears_without_polling_loop()
|
||||
{
|
||||
|
||||
@@ -12,6 +12,7 @@ public sealed class FocasCapabilityTests
|
||||
// ---- ITagDiscovery ----
|
||||
|
||||
/// <summary>Verifies that DiscoverAsync emits pre-declared tags.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task DiscoverAsync_emits_pre_declared_tags()
|
||||
{
|
||||
@@ -41,6 +42,7 @@ public sealed class FocasCapabilityTests
|
||||
// ---- ISubscribable ----
|
||||
|
||||
/// <summary>Verifies that the initial subscription poll raises an OnDataChange event.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Subscribe_initial_poll_raises_OnDataChange()
|
||||
{
|
||||
@@ -67,6 +69,7 @@ public sealed class FocasCapabilityTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that ShutdownAsync cancels active subscriptions.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ShutdownAsync_cancels_active_subscriptions()
|
||||
{
|
||||
@@ -97,6 +100,7 @@ public sealed class FocasCapabilityTests
|
||||
// ---- IHostConnectivityProbe ----
|
||||
|
||||
/// <summary>Verifies that GetHostStatuses returns one entry per device.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetHostStatuses_returns_entry_per_device()
|
||||
{
|
||||
@@ -115,6 +119,7 @@ public sealed class FocasCapabilityTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that the probe transitions to Running on successful connection.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Probe_transitions_to_Running_on_success()
|
||||
{
|
||||
@@ -142,6 +147,7 @@ public sealed class FocasCapabilityTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that the probe transitions to Stopped on connection failure.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Probe_transitions_to_Stopped_on_failure()
|
||||
{
|
||||
@@ -171,6 +177,7 @@ public sealed class FocasCapabilityTests
|
||||
// ---- IPerCallHostResolver ----
|
||||
|
||||
/// <summary>Verifies that ResolveHost returns the declared device for a known tag.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ResolveHost_returns_declared_device_for_known_tag()
|
||||
{
|
||||
@@ -195,6 +202,7 @@ public sealed class FocasCapabilityTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that ResolveHost falls back to the first device for unknown tags.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ResolveHost_falls_back_to_first_device_for_unknown()
|
||||
{
|
||||
@@ -209,6 +217,7 @@ public sealed class FocasCapabilityTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that ResolveHost falls back to the driver instance ID when no devices are configured.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ResolveHost_falls_back_to_DriverInstanceId_when_no_devices()
|
||||
{
|
||||
@@ -235,40 +244,27 @@ public sealed class FocasCapabilityTests
|
||||
/// <summary>Gets the list of recorded variable calls.</summary>
|
||||
public List<(string BrowseName, DriverAttributeInfo Info)> Variables { get; } = new();
|
||||
|
||||
/// <summary>Records a folder call.</summary>
|
||||
/// <param name="browseName">The browse name of the folder.</param>
|
||||
/// <param name="displayName">The display name of the folder.</param>
|
||||
/// <returns>This builder for chaining.</returns>
|
||||
/// <inheritdoc />
|
||||
public IAddressSpaceBuilder Folder(string browseName, string displayName)
|
||||
{ Folders.Add((browseName, displayName)); return this; }
|
||||
|
||||
/// <summary>Records a variable call.</summary>
|
||||
/// <param name="browseName">The browse name of the variable.</param>
|
||||
/// <param name="displayName">The display name of the variable.</param>
|
||||
/// <param name="info">The driver attribute information.</param>
|
||||
/// <returns>A variable handle for the recorded variable.</returns>
|
||||
/// <inheritdoc />
|
||||
public IVariableHandle Variable(string browseName, string displayName, DriverAttributeInfo info)
|
||||
{ Variables.Add((browseName, info)); return new Handle(info.FullName); }
|
||||
|
||||
/// <summary>Records a property call (no-op).</summary>
|
||||
/// <param name="_">The property name (unused).</param>
|
||||
/// <param name="__">The property data type (unused).</param>
|
||||
/// <param name="___">The property value (unused).</param>
|
||||
/// <inheritdoc />
|
||||
public void AddProperty(string _, DriverDataType __, object? ___) { }
|
||||
|
||||
private sealed class Handle(string fullRef) : IVariableHandle
|
||||
{
|
||||
/// <summary>Gets the full reference.</summary>
|
||||
/// <inheritdoc />
|
||||
public string FullReference => fullRef;
|
||||
/// <summary>Marks as alarm condition.</summary>
|
||||
/// <param name="info">The alarm condition information.</param>
|
||||
/// <returns>An alarm condition sink.</returns>
|
||||
/// <inheritdoc />
|
||||
public IAlarmConditionSink MarkAsAlarmCondition(AlarmConditionInfo info) => new NullSink();
|
||||
}
|
||||
/// <summary>Null alarm condition sink.</summary>
|
||||
private sealed class NullSink : IAlarmConditionSink {
|
||||
/// <summary>Handles transition (no-op).</summary>
|
||||
/// <param name="args">The alarm event arguments (unused).</param>
|
||||
/// <inheritdoc />
|
||||
public void OnTransition(AlarmEventArgs args) { }
|
||||
}
|
||||
}
|
||||
|
||||
+13
-16
@@ -21,6 +21,7 @@ public sealed class FocasDriverMediumFindingsTests
|
||||
// ---- Driver.FOCAS-003: unknown DeviceHostAddress fails at InitializeAsync ----
|
||||
|
||||
/// <summary>Verifies that initialization throws when a tag references an undeclared device.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task InitializeAsync_throws_when_tag_DeviceHostAddress_not_in_Devices()
|
||||
{
|
||||
@@ -43,6 +44,7 @@ public sealed class FocasDriverMediumFindingsTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that initialization errors name the offending tag.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task InitializeAsync_throws_naming_the_offending_tag()
|
||||
{
|
||||
@@ -64,6 +66,7 @@ public sealed class FocasDriverMediumFindingsTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that initialization succeeds when all tags reference declared devices.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task InitializeAsync_succeeds_when_all_tags_reference_declared_devices()
|
||||
{
|
||||
@@ -90,6 +93,7 @@ public sealed class FocasDriverMediumFindingsTests
|
||||
// ---- Driver.FOCAS-004: all FOCAS user tags advertised as ViewOnly ----
|
||||
|
||||
/// <summary>Verifies that all user tags are advertised as ViewOnly regardless of Writable setting.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task DiscoverAsync_all_user_tags_are_ViewOnly_regardless_of_Writable_field()
|
||||
{
|
||||
@@ -119,6 +123,7 @@ public sealed class FocasDriverMediumFindingsTests
|
||||
// ---- Driver.FOCAS-005: Volatile-guarded _health survives concurrent reads ----
|
||||
|
||||
/// <summary>Verifies that GetHealth reflects state updated from concurrent reads.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task GetHealth_reflects_state_updated_from_concurrent_reads()
|
||||
{
|
||||
@@ -148,6 +153,7 @@ public sealed class FocasDriverMediumFindingsTests
|
||||
// ---- Driver.FOCAS-006: EnsureConnectedAsync recreates a disposed/stale client ----
|
||||
|
||||
/// <summary>Verifies that reads recover after client is externally disposed.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Read_recovers_after_client_is_externally_disposed()
|
||||
{
|
||||
@@ -184,6 +190,7 @@ public sealed class FocasDriverMediumFindingsTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that reads dispose stale clients before creating fresh ones.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Read_disposes_stale_client_before_creating_fresh_one()
|
||||
{
|
||||
@@ -257,41 +264,31 @@ public sealed class FocasDriverMediumFindingsTests
|
||||
/// <summary>Gets or sets the list of added folders.</summary>
|
||||
public List<(string BrowseName, string DisplayName)> Folders { get; } = new();
|
||||
|
||||
/// <summary>Records a folder and returns this builder for chaining.</summary>
|
||||
/// <param name="browseName">The OPC UA browse name for the folder.</param>
|
||||
/// <param name="displayName">The display name for the folder.</param>
|
||||
/// <inheritdoc />
|
||||
public IAddressSpaceBuilder Folder(string browseName, string displayName)
|
||||
{ Folders.Add((browseName, displayName)); return this; }
|
||||
|
||||
/// <summary>Records a variable and returns a handle for it.</summary>
|
||||
/// <param name="browseName">The OPC UA browse name for the variable.</param>
|
||||
/// <param name="displayName">The display name for the variable.</param>
|
||||
/// <param name="info">The driver attribute information for the variable.</param>
|
||||
/// <inheritdoc />
|
||||
public IVariableHandle Variable(string browseName, string displayName, DriverAttributeInfo info)
|
||||
{ Variables.Add((browseName, info)); return new Handle(info.FullName); }
|
||||
|
||||
/// <summary>No-op property addition for test compatibility.</summary>
|
||||
/// <param name="_">The property name (unused).</param>
|
||||
/// <param name="__">The property data type (unused).</param>
|
||||
/// <param name="___">The property value (unused).</param>
|
||||
/// <inheritdoc />
|
||||
public void AddProperty(string _, DriverDataType __, object? ___) { }
|
||||
|
||||
/// <summary>Test variable handle implementation.</summary>
|
||||
private sealed class Handle(string fullRef) : IVariableHandle
|
||||
{
|
||||
/// <summary>Gets the full reference path of this variable.</summary>
|
||||
/// <inheritdoc />
|
||||
public string FullReference => fullRef;
|
||||
|
||||
/// <summary>Marks this variable as an alarm condition and returns a sink for it.</summary>
|
||||
/// <param name="info">The alarm condition information.</param>
|
||||
/// <inheritdoc />
|
||||
public IAlarmConditionSink MarkAsAlarmCondition(AlarmConditionInfo info) => new NullSink();
|
||||
}
|
||||
|
||||
/// <summary>No-op alarm condition sink for testing.</summary>
|
||||
private sealed class NullSink : IAlarmConditionSink
|
||||
{
|
||||
/// <summary>Handles alarm condition transitions (no-op for testing).</summary>
|
||||
/// <param name="args">The alarm event arguments.</param>
|
||||
/// <inheritdoc />
|
||||
public void OnTransition(AlarmEventArgs args) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ public sealed class FocasFactoryConfigTests
|
||||
// ---- Driver.FOCAS-002: fixed-tree bootstrap must not declare a false ProgramInfo capability ----
|
||||
|
||||
/// <summary>Verifies that ProgramInfo is marked unsupported when probe throws.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task FixedTree_bootstrap_marks_ProgramInfo_unsupported_when_probe_throws()
|
||||
{
|
||||
@@ -146,6 +147,7 @@ public sealed class FocasFactoryConfigTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that ProgramInfo is marked supported when probe succeeds.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task FixedTree_bootstrap_marks_ProgramInfo_supported_when_probe_succeeds()
|
||||
{
|
||||
|
||||
@@ -7,6 +7,7 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests;
|
||||
public sealed class FocasHandleRecycleTests
|
||||
{
|
||||
/// <summary>Verifies that the recycle loop disposes clients on interval and reopens fresh ones.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Recycle_loop_disposes_client_on_interval_reads_reopen_fresh_one()
|
||||
{
|
||||
@@ -40,6 +41,7 @@ public sealed class FocasHandleRecycleTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that the recycle loop stays off when not enabled.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Recycle_loop_stays_off_when_not_enabled()
|
||||
{
|
||||
|
||||
@@ -31,6 +31,7 @@ public sealed class FocasLoggingTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that probe loop logs when an exception is swallowed.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ProbeLoop_logs_when_an_exception_is_swallowed()
|
||||
{
|
||||
@@ -90,9 +91,11 @@ public sealed class FocasLoggingTests
|
||||
/// <summary>Begins a logging scope.</summary>
|
||||
/// <param name="state">The scope state.</param>
|
||||
/// <typeparam name="TState">The type of the state.</typeparam>
|
||||
/// <returns>A disposable scope object.</returns>
|
||||
public IDisposable BeginScope<TState>(TState state) where TState : notnull => NullScope.Instance;
|
||||
/// <summary>Checks if logging is enabled for the specified level.</summary>
|
||||
/// <param name="logLevel">The log level.</param>
|
||||
/// <returns><c>true</c> if logging is enabled for <paramref name="logLevel"/>; otherwise, <c>false</c>.</returns>
|
||||
public bool IsEnabled(LogLevel logLevel) => true;
|
||||
/// <summary>Logs a message.</summary>
|
||||
/// <param name="logLevel">The log level.</param>
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class FocasLowFindingsTests
|
||||
/// <summary>
|
||||
/// Verifies that ReadAsync uses cached FocasAddress when tag definition has a malformed address after init.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ReadAsync_uses_cached_FocasAddress_when_tag_definition_has_a_malformed_address_after_init()
|
||||
{
|
||||
@@ -59,6 +60,7 @@ public sealed class FocasLowFindingsTests
|
||||
/// <summary>
|
||||
/// Verifies that WriteAsync also uses cached FocasAddress.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task WriteAsync_uses_cached_FocasAddress_too()
|
||||
{
|
||||
@@ -99,6 +101,7 @@ public sealed class FocasLowFindingsTests
|
||||
/// <summary>
|
||||
/// Verifies that ProbeLoop cancels a slow ProbeAsync at Probe Timeout.
|
||||
/// </summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ProbeLoop_cancels_a_slow_ProbeAsync_at_Probe_Timeout()
|
||||
{
|
||||
|
||||
@@ -66,6 +66,7 @@ public sealed class FocasPmcBitRmwTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a bit set operation surfaces as Good status and flips the bit.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Bit_set_surfaces_as_Good_status_and_flips_bit()
|
||||
{
|
||||
@@ -81,6 +82,7 @@ public sealed class FocasPmcBitRmwTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that clearing a bit preserves other bits.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Bit_clear_preserves_other_bits()
|
||||
{
|
||||
@@ -95,6 +97,7 @@ public sealed class FocasPmcBitRmwTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that subsequent bit sets in the same byte compose correctly.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Subsequent_bit_sets_in_same_byte_compose_correctly()
|
||||
{
|
||||
@@ -112,6 +115,7 @@ public sealed class FocasPmcBitRmwTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that bit writes to different bytes do not contend.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task Bit_write_to_different_bytes_does_not_contend()
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@ public sealed class FocasReadWriteTests
|
||||
// ---- Read ----
|
||||
|
||||
/// <summary>Verifies that an unknown reference maps to BadNodeIdUnknown.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Unknown_reference_maps_to_BadNodeIdUnknown()
|
||||
{
|
||||
@@ -34,6 +35,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a successful PMC read returns a Good status value.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Successful_PMC_read_returns_Good_value()
|
||||
{
|
||||
@@ -48,6 +50,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that parameter reads route through the FocasAddress Parameter kind.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Parameter_read_routes_through_FocasAddress_Parameter_kind()
|
||||
{
|
||||
@@ -62,6 +65,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that macro reads route through the FocasAddress Macro kind.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Macro_read_routes_through_FocasAddress_Macro_kind()
|
||||
{
|
||||
@@ -75,6 +79,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that repeated reads reuse the connection.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Repeat_read_reuses_connection()
|
||||
{
|
||||
@@ -91,6 +96,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that FOCAS error statuses map correctly via the status mapper.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task FOCAS_error_status_maps_via_status_mapper()
|
||||
{
|
||||
@@ -109,6 +115,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a read exception surfaces BadCommunicationError.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Read_exception_surfaces_BadCommunicationError()
|
||||
{
|
||||
@@ -123,6 +130,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a connection failure disposes the client and surfaces BadCommunicationError.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Connect_failure_disposes_client_and_surfaces_BadCommunicationError()
|
||||
{
|
||||
@@ -137,6 +145,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that batched reads preserve order across different address areas.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Batched_reads_preserve_order_across_areas()
|
||||
{
|
||||
@@ -164,6 +173,7 @@ public sealed class FocasReadWriteTests
|
||||
// ---- Write ----
|
||||
|
||||
/// <summary>Verifies that a non-writable tag write is rejected with BadNotWritable.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Non_writable_tag_rejected_with_BadNotWritable()
|
||||
{
|
||||
@@ -177,6 +187,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a successful write logs the address, type, and value.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Successful_write_logs_address_type_value()
|
||||
{
|
||||
@@ -195,6 +206,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that write status codes map correctly via the FocasStatusMapper.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Write_status_code_maps_via_FocasStatusMapper()
|
||||
{
|
||||
@@ -214,6 +226,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that batched writes preserve order across different outcomes.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Batch_write_preserves_order_across_outcomes()
|
||||
{
|
||||
@@ -243,6 +256,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that cancellation signals are propagated.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task Cancellation_propagates()
|
||||
{
|
||||
@@ -260,6 +274,7 @@ public sealed class FocasReadWriteTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies that ShutdownAsync disposes the client.</summary>
|
||||
/// <returns>A task that represents the asynchronous test operation.</returns>
|
||||
[Fact]
|
||||
public async Task ShutdownAsync_disposes_client()
|
||||
{
|
||||
|
||||
@@ -201,6 +201,7 @@ public sealed class FocasScaffoldingTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies InitializeAsync parses device addresses correctly.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task InitializeAsync_parses_device_addresses()
|
||||
{
|
||||
@@ -221,6 +222,7 @@ public sealed class FocasScaffoldingTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies InitializeAsync faults on malformed addresses.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task InitializeAsync_malformed_address_faults()
|
||||
{
|
||||
@@ -235,6 +237,7 @@ public sealed class FocasScaffoldingTests
|
||||
}
|
||||
|
||||
/// <summary>Verifies ShutdownAsync clears all devices.</summary>
|
||||
/// <returns>A task that represents the asynchronous operation.</returns>
|
||||
[Fact]
|
||||
public async Task ShutdownAsync_clears_devices()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user