using Shouldly; using Xunit; using ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport.Cip; namespace ZB.MOM.WW.OtOpcUa.Driver.Ab.Transport.Tests.Cip; public sealed class MultipleServicePacketTests { [Fact] public void Msp_offsets_are_measured_from_the_count_field() { var a = new byte[] { 0x4C, 0x02, 0x91, 0x01, 0x41, 0x00, 0x01, 0x00 }; var b = new byte[] { 0x4C, 0x02, 0x91, 0x01, 0x42, 0x00, 0x01, 0x00 }; Convert.ToHexString(MultipleServicePacket.Build([a, b])).ShouldBe( "0A02200224010200" + "0600" + "0E00" + Convert.ToHexString(a) + Convert.ToHexString(b)); MultipleServicePacket.BuildSize([8, 8]).ShouldBe(6 + 2 + 4 + 16); } [Fact] public void BuildSize_equals_built_length() { byte[][] reqs = [new byte[7], new byte[20], new byte[1]]; MultipleServicePacket.Build(reqs).Length.ShouldBe(MultipleServicePacket.BuildSize([7, 20, 1])); } [Fact] public void Parse_splits_replies() { // outer reply data: count 2, offsets 6 and 14, reply1 (8 bytes), reply2 (6 bytes) var r1 = Convert.FromHexString("CC000000C400" + "0100"); // DINT-typed read reply, 8 bytes var r2 = Convert.FromHexString("CD000000" + "0000"); // write ok + 2 extra bytes var data = Convert.FromHexString("0200" + "0600" + "0E00").Concat(r1).Concat(r2).ToArray(); var outer = new CipReply(0x0A, 0, [], data); var replies = MultipleServicePacket.Parse(outer, 2); replies.Count.ShouldBe(2); replies[0].Service.ShouldBe((byte)0x4C); Convert.ToHexString(replies[0].Data.ToArray()).ShouldBe("C4000100"); replies[1].Service.ShouldBe((byte)0x4D); } [Fact] public void Parse_embedded_error_status_is_kept_per_reply() { var r1 = Convert.FromHexString("CC000400"); var data = Convert.FromHexString("0100" + "0400").Concat(r1).ToArray(); MultipleServicePacket.Parse(new CipReply(0x0A, 0x1E, [], data), 1)[0].GeneralStatus.ShouldBe((byte)0x04); } [Fact] public void Parse_wrong_count_throws() => Should.Throw(() => MultipleServicePacket.Parse(new CipReply(0x0A, 0, [], Convert.FromHexString("0100" + "0400" + "CC000000")), 2)); }