review(Driver.S7): reject writable array tags at init instead of silent write failure
Re-review at 7286d320. S7-015 (Medium): a Writable array tag had no WriteArrayAsync path
and silently returned BadCommunicationError on write; now rejected at init with a clear
NotSupportedException (read-only arrays still accepted) + TDD. S7-016 (factory JSON can't
produce array tags; needs AdminUI DTO) deferred.
This commit is contained in:
@@ -225,4 +225,61 @@ public sealed class S7DriverScaffoldTests
|
||||
|
||||
drv.GetHealth().State.ShouldBe(DriverState.Faulted);
|
||||
}
|
||||
|
||||
// ── Driver.S7-015 — writable array tag must fail fast at init ────────────────────────
|
||||
//
|
||||
// Array reads are implemented (ReadArrayAsync / DecodeArrayBlock), but WriteOneAsync has
|
||||
// no WriteArrayAsync path. Without the init guard a writable array node is discovered and
|
||||
// accepted, then every write returns BadCommunicationError (InvalidCastException from
|
||||
// BoxValueForWrite receiving a typed array). Fail fast at init instead.
|
||||
|
||||
/// <summary>Verifies that a writable non-wide array (e.g., Int16[4]) is rejected at init
|
||||
/// with a clear "array writes not yet supported" message — Driver.S7-015.</summary>
|
||||
[Theory]
|
||||
[InlineData(S7DataType.Bool, "DB1.DBX0.0", 4)]
|
||||
[InlineData(S7DataType.Byte, "DB1.DBB0", 8)]
|
||||
[InlineData(S7DataType.Int16, "DB1.DBW0", 4)]
|
||||
[InlineData(S7DataType.UInt16, "DB1.DBW0", 4)]
|
||||
[InlineData(S7DataType.Int32, "DB1.DBD0", 2)]
|
||||
[InlineData(S7DataType.UInt32, "DB1.DBD0", 2)]
|
||||
[InlineData(S7DataType.Float32,"DB1.DBD0", 2)]
|
||||
public async Task Initialize_rejects_writable_array_tag_with_NotSupportedException(
|
||||
S7DataType dt, string addr, int count)
|
||||
{
|
||||
var opts = new S7DriverOptions
|
||||
{
|
||||
Host = "192.0.2.1",
|
||||
Timeout = TimeSpan.FromMilliseconds(250),
|
||||
Tags = [new S7TagDefinition("ArrTag", addr, dt, Writable: true, ArrayCount: count)],
|
||||
};
|
||||
using var drv = new S7Driver(opts, $"s7-writable-arr-{dt}");
|
||||
|
||||
var ex = await Should.ThrowAsync<NotSupportedException>(async () =>
|
||||
await drv.InitializeAsync("{}", TestContext.Current.CancellationToken));
|
||||
ex.Message.ShouldContain("ArrTag");
|
||||
ex.Message.ShouldContain("array", Case.Insensitive);
|
||||
ex.Message.ShouldContain("write", Case.Insensitive);
|
||||
|
||||
drv.GetHealth().State.ShouldBe(DriverState.Faulted);
|
||||
}
|
||||
|
||||
/// <summary>Verifies that a read-only (Writable=false) array passes the init guard —
|
||||
/// array reads are fully implemented; only writes are gated.</summary>
|
||||
[Fact]
|
||||
public async Task Initialize_accepts_readonly_array_tag()
|
||||
{
|
||||
var opts = new S7DriverOptions
|
||||
{
|
||||
Host = "192.0.2.1",
|
||||
Timeout = TimeSpan.FromMilliseconds(250),
|
||||
Tags = [new S7TagDefinition("ReadArr", "DB1.DBW0", S7DataType.Int16, Writable: false, ArrayCount: 4)],
|
||||
};
|
||||
using var drv = new S7Driver(opts, "s7-readonly-arr");
|
||||
|
||||
// Must NOT throw NotSupportedException — the failure must be the TCP connect (unreachable host).
|
||||
var ex = await Should.ThrowAsync<Exception>(async () =>
|
||||
await drv.InitializeAsync("{}", TestContext.Current.CancellationToken));
|
||||
ex.ShouldNotBeOfType<NotSupportedException>(
|
||||
"read-only arrays are fully supported — the failure must be the TCP connect, not the array guard");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user