fix(abcip): accept module-defined I/O tag paths (Local:1:I.Data, ABB_OmniCore:I.X)
Live read-only check: a production CompactLogix lists the module tag ABB_OmniCore:I in @tags and libplctag reads ABB_OmniCore:I.ConnectionFaulted without complaint, but the driver refused the path as malformed (identifier rule had no colon) and reported the tag BadCommunicationError. Colon-separated identifier/slot parts are now legal in the controller-scope base segment only (never past it, never under Program: scope).
This commit is contained in:
@@ -128,6 +128,41 @@ public sealed class AbCipTagPathTests
|
||||
AbCipTagPath.TryParse(input).ShouldBeNull();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Module-defined I/O tags carry colons in their base name (<c>Local:1:I</c>,
|
||||
/// <c>ABB_OmniCore:I</c>). Seen live: a CompactLogix lists <c>ABB_OmniCore:I</c> in
|
||||
/// <c>@tags</c>, libplctag reads <c>ABB_OmniCore:I.ConnectionFaulted</c> fine, and the driver
|
||||
/// refused it as a malformed path.
|
||||
/// </summary>
|
||||
/// <param name="input">A module tag path.</param>
|
||||
/// <param name="baseName">The expected base (first segment) name.</param>
|
||||
[Theory]
|
||||
[InlineData("ABB_OmniCore:I.ConnectionFaulted", "ABB_OmniCore:I")]
|
||||
[InlineData("Local:1:I.Data", "Local:1:I")]
|
||||
[InlineData("Local:2:O.Data.3", "Local:2:O")]
|
||||
[InlineData("Rack1:3:C.Ch0Config.RangeType", "Rack1:3:C")]
|
||||
public void Module_IO_tag_base_names_with_colons_parse_and_round_trip(string input, string baseName)
|
||||
{
|
||||
var parsed = AbCipTagPath.TryParse(input);
|
||||
parsed.ShouldNotBeNull();
|
||||
parsed.ProgramScope.ShouldBeNull();
|
||||
parsed.Segments[0].Name.ShouldBe(baseName);
|
||||
parsed.ToLibplctagName().ShouldBe(input);
|
||||
}
|
||||
|
||||
/// <summary>A colon is only legal in the base name, and never as a dangling or doubled separator.</summary>
|
||||
/// <param name="input">A malformed path.</param>
|
||||
[Theory]
|
||||
[InlineData("Motor.Sub:I")] // colon past the base segment
|
||||
[InlineData("Local::I.Data")] // empty colon part
|
||||
[InlineData("Local:1:.Data")] // trailing colon
|
||||
[InlineData(":Local.Data")] // leading colon
|
||||
[InlineData("Program:P.Local:1:I")] // module tags are controller-scope only
|
||||
public void Colons_outside_a_module_base_name_are_rejected(string input)
|
||||
{
|
||||
AbCipTagPath.TryParse(input).ShouldBeNull();
|
||||
}
|
||||
|
||||
/// <summary>Verifies that identifiers with underscores are accepted.</summary>
|
||||
[Fact]
|
||||
public void Ident_with_underscore_accepted()
|
||||
|
||||
Reference in New Issue
Block a user