7892eb13a8
CIP codec (#564): PatchU16 bounds guard; CipReply content equality; CipPath port/length/ASCII/odd/oversize validation with ArgumentException for malformed tag names and routes; CipPath.MessageRouter/ConnectionManager are now ReadOnlySpan<byte>; refused Forward Open surfaces ForwardOpenRefusedException with structured general/extended status; test CaptureFile uses BinaryPrimitives. EncapsulationClient (#565): frame write bounded by the exchange timeout, which faults (never cancels) the connection; finite positive timeouts enforced at every entry point; gate wait bounded by the timeout; deterministic reorder of the 300 ms test; new dispose-during-drain, gate-wait and RegisterSession zero-context tests. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
58 lines
2.4 KiB
C#
58 lines
2.4 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport.Tests;
|
|
|
|
public sealed class AbStatusCodesTests
|
|
{
|
|
[Theory]
|
|
[InlineData((byte)0x00, AbStatus.Ok)]
|
|
[InlineData((byte)0x04, AbStatus.NotFound)]
|
|
[InlineData((byte)0x05, AbStatus.NotFound)]
|
|
[InlineData((byte)0x16, AbStatus.NotFound)]
|
|
[InlineData((byte)0x06, AbStatus.Partial)]
|
|
[InlineData((byte)0x08, AbStatus.Unsupported)]
|
|
[InlineData((byte)0x0F, AbStatus.NotAllowed)]
|
|
[InlineData((byte)0x10, AbStatus.DeviceStateConflict)]
|
|
[InlineData((byte)0x13, AbStatus.TooSmall)]
|
|
[InlineData((byte)0x15, AbStatus.TooLarge)]
|
|
[InlineData((byte)0x0B, AbStatus.Ok)]
|
|
[InlineData((byte)0x0A, AbStatus.OutOfBounds)]
|
|
[InlineData((byte)0x0C, AbStatus.DeviceStateConflict)]
|
|
[InlineData((byte)0x0E, AbStatus.NotAllowed)]
|
|
[InlineData((byte)0x1E, AbStatus.BadReply)]
|
|
[InlineData((byte)0x01, AbStatus.BadReply)]
|
|
public void Cip_general_status_maps(byte general, AbStatus expected) =>
|
|
AbStatusCodes.FromCip(general, ReadOnlySpan<ushort>.Empty).ShouldBe(expected);
|
|
|
|
[Theory]
|
|
[InlineData((ushort)0x2105, AbStatus.OutOfBounds)]
|
|
[InlineData((ushort)0x2107, AbStatus.TypeMismatch)]
|
|
[InlineData((ushort)0x9999, AbStatus.BadReply)]
|
|
public void General_status_FF_maps_by_extended_status(ushort ext, AbStatus expected) =>
|
|
AbStatusCodes.FromCip(0xFF, [ext]).ShouldBe(expected);
|
|
|
|
[Fact]
|
|
public void General_status_FF_with_no_extended_status_is_BadReply() =>
|
|
AbStatusCodes.FromCip(0xFF, ReadOnlySpan<ushort>.Empty).ShouldBe(AbStatus.BadReply);
|
|
|
|
[Theory]
|
|
[InlineData((byte)0x00, null, AbStatus.Ok)]
|
|
[InlineData((byte)0x10, null, AbStatus.Unsupported)]
|
|
[InlineData((byte)0x20, null, AbStatus.NotFound)]
|
|
[InlineData((byte)0x30, null, AbStatus.NotAllowed)]
|
|
[InlineData((byte)0x40, null, AbStatus.DeviceStateConflict)]
|
|
[InlineData((byte)0xF0, (byte)0x06, AbStatus.NotFound)]
|
|
[InlineData((byte)0xF0, (byte)0x07, AbStatus.NotFound)]
|
|
[InlineData((byte)0xF0, (byte)0x0A, AbStatus.BadReply)]
|
|
public void Pccc_status_maps(byte sts, byte? ext, AbStatus expected) =>
|
|
AbStatusCodes.FromPccc(sts, ext).ShouldBe(expected);
|
|
|
|
[Fact]
|
|
public void Ok_is_zero_and_every_error_is_negative()
|
|
{
|
|
((int)AbStatus.Ok).ShouldBe(0);
|
|
foreach (var s in Enum.GetValues<AbStatus>().Where(s => s is not AbStatus.Ok and not AbStatus.Pending))
|
|
((int)s).ShouldBeLessThan(0);
|
|
}
|
|
}
|