f8bf067243
Re-review at 7286d320. -008 (Medium): S7CommandBase.ValidateEndpoint (port range + timeout>0)
in all commands +tests. -009 clean OperationCanceledException handling; -010 FlushLogging()
in subscribe finally; -011 lock console writes in OnDataChange. -012 (Verdict headline) deferred.
72 lines
3.1 KiB
C#
72 lines
3.1 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.S7.Cli.Tests;
|
|
|
|
/// <summary>
|
|
/// Driver.S7.Cli-009: every S7 CLI command that catches
|
|
/// <see cref="System.OperationCanceledException"/> must use the
|
|
/// <c>when (ct.IsCancellationRequested)</c> exception filter so that a
|
|
/// driver-internal timeout (thrown with a different cancellation token) does not get
|
|
/// mis-handled as a user Ctrl+C. Source-level check mirrors
|
|
/// <see cref="CommandDisposalConventionsTests"/>.
|
|
/// </summary>
|
|
[Trait("Category", "Unit")]
|
|
public sealed class CancellationHandlingTests
|
|
{
|
|
private static readonly string CommandsDir = LocateCommandsDir();
|
|
|
|
/// <summary>
|
|
/// Verifies that ProbeCommand uses the ct.IsCancellationRequested guard on its
|
|
/// OperationCanceledException catch block so a driver-internal timeout is not
|
|
/// swallowed as a user-cancelled operation.
|
|
/// </summary>
|
|
[Fact]
|
|
public void ProbeCommand_uses_ct_IsCancellationRequested_guard()
|
|
{
|
|
// Driver.S7.Cli-009: the bare `catch (OperationCanceledException)` without a
|
|
// `when` filter would mis-classify a driver-internal timeout as a Ctrl+C and
|
|
// either re-throw from the wrong catch block or swallow the error.
|
|
var source = File.ReadAllText(Path.Combine(CommandsDir, "ProbeCommand.cs"));
|
|
source.ShouldContain("when (ct.IsCancellationRequested)");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that ReadCommand provides quiet cancellation handling for Ctrl+C.
|
|
/// </summary>
|
|
[Fact]
|
|
public void ReadCommand_handles_OperationCanceledException_quietly()
|
|
{
|
|
// Driver.S7.Cli-009: ReadCommand must catch OperationCanceledException and
|
|
// print "Cancelled." (matching the Modbus CLI pattern) rather than letting
|
|
// CliFx render an unhandled exception on Ctrl+C.
|
|
var source = File.ReadAllText(Path.Combine(CommandsDir, "ReadCommand.cs"));
|
|
source.ShouldContain("OperationCanceledException");
|
|
source.ShouldContain("Cancelled.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifies that WriteCommand provides quiet cancellation handling for Ctrl+C.
|
|
/// </summary>
|
|
[Fact]
|
|
public void WriteCommand_handles_OperationCanceledException_quietly()
|
|
{
|
|
// Driver.S7.Cli-009: WriteCommand must catch OperationCanceledException and
|
|
// print "Cancelled." (matching the Modbus CLI pattern) rather than letting
|
|
// CliFx render an unhandled exception on Ctrl+C.
|
|
var source = File.ReadAllText(Path.Combine(CommandsDir, "WriteCommand.cs"));
|
|
source.ShouldContain("OperationCanceledException");
|
|
source.ShouldContain("Cancelled.");
|
|
}
|
|
|
|
private static string LocateCommandsDir()
|
|
{
|
|
var dir = new DirectoryInfo(AppContext.BaseDirectory);
|
|
while (dir is not null && !File.Exists(Path.Combine(dir.FullName, "ZB.MOM.WW.OtOpcUa.slnx")))
|
|
dir = dir.Parent;
|
|
dir.ShouldNotBeNull("Could not find solution root (ZB.MOM.WW.OtOpcUa.slnx).");
|
|
return Path.Combine(
|
|
dir!.FullName, "src", "Drivers", "Cli", "ZB.MOM.WW.OtOpcUa.Driver.S7.Cli", "Commands");
|
|
}
|
|
}
|