fix(s7): refuse unservable tag shapes per tag at every gate (R07:H3, R07:U4)
The init-time tag guards THREW: one mis-authored tag (DB1.DBZ0, DB1.DBW0 typed Float64, T5 typed Int32, a writable Bool array) faulted the whole driver and the actor retried the same init every 10 s forever, darkening every tag on the PLC. Neither the editor nor the deploy gate checked any of it. - S7AddressParser moves to S7.Contracts (same namespace) and a new S7TagShapeRules there is the single authority on servable shapes. - S7TagDefinitionFactory.FromTagConfig applies it, so the AdminUI editor, the deploy gate (Inspect, with the specific reason) and the driver init refuse the same tags. Init now skips a refused tag (ISkippedTagReporter) instead of throwing; the throwing RejectUnsupportedTagConfigs is gone. - New rules on top of the old guards: a narrow type at the wrong access width (every read failed) and a Bool array not starting at bit 0 (U4: DB1.DBX0.3 silently read bit 0 of bytes 0..n). - AdminUI test fixtures that used addresses the driver could never serve (DB1.DBS0, a browse "SomeAddress", Int32/Float32 on DBW) now use real ones. Refs #742 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -158,23 +158,9 @@ public sealed class S7DriverCodeReviewFixTests2
|
||||
[InlineData(S7DataType.DateTime)]
|
||||
public async Task Initialize_rejects_wide_type_at_non_byte_address_with_NotSupportedException(S7DataType dt)
|
||||
{
|
||||
var opts = new S7DriverOptions
|
||||
{
|
||||
Host = "192.0.2.1",
|
||||
Timeout = TimeSpan.FromMilliseconds(250),
|
||||
// DB1.DBD0 is a DWord (non-byte) address — guard-(b) must fault on the address shape
|
||||
// for a wide type. (At a byte address like DB1.DBB0 the 8-byte numerics round-trip;
|
||||
// see S7ScalarBlockTests.)
|
||||
RawTags = S7RawTags.Entries(new S7TagDefinition("X", "DB1.DBD0", dt)),
|
||||
};
|
||||
using var drv = new S7Driver(opts, $"s7-wide-nonbyte-{dt}");
|
||||
|
||||
var ex = await Should.ThrowAsync<NotSupportedException>(async () =>
|
||||
await drv.InitializeAsync("{}", TestContext.Current.CancellationToken));
|
||||
ex.Message.ShouldContain(dt.ToString());
|
||||
|
||||
var health = drv.GetHealth();
|
||||
health.State.ShouldBe(DriverState.Faulted);
|
||||
// DB1.DBD0 is a DWord (non-byte) address — a wide type there would mis-frame its value. (At a
|
||||
// byte address like DB1.DBB0 the 8-byte numerics round-trip; see S7ScalarBlockTests.)
|
||||
await S7TagSkipAssert.RefusedPerTagAsync(new S7TagDefinition("X", "DB1.DBD0", dt), dt.ToString(), "byte-addressed");
|
||||
}
|
||||
|
||||
/// <summary>Verifies that Initialize accepts implemented data types.</summary>
|
||||
|
||||
Reference in New Issue
Block a user