using System.Buffers.Binary; using SuiteLink.Client.Protocol; namespace SuiteLink.Client.Tests.Protocol; public sealed class SuiteLinkHandshakeCodecTests { [Fact] public void EncodeNormalQueryHandshake_WritesLengthMagicsAndIdentityStrings() { var bytes = SuiteLinkHandshakeCodec.EncodeNormalQueryHandshake( targetApplication: "Intouch", sourceNode: "NodeA", sourceUser: "UserA"); Assert.Equal(bytes.Length - 1, bytes[0]); Assert.Equal(SuiteLinkHandshakeCodec.QueryMagic.ToArray(), bytes.AsSpan(1, 16).ToArray()); Assert.Equal(SuiteLinkHandshakeCodec.UnknownQueryMagic.ToArray(), bytes.AsSpan(17, 16).ToArray()); Assert.Equal(1u, BinaryPrimitives.ReadUInt32LittleEndian(bytes.AsSpan(33, 4))); var expectedApp = SuiteLinkEncoding.EncodeNullTerminatedUtf16("Intouch"); var expectedNode = SuiteLinkEncoding.EncodeNullTerminatedUtf16("NodeA"); var expectedUser = SuiteLinkEncoding.EncodeNullTerminatedUtf16("UserA"); var payload = bytes.AsSpan(37); Assert.True(payload.StartsWith(expectedApp)); payload = payload[expectedApp.Length..]; Assert.True(payload.StartsWith(expectedNode)); payload = payload[expectedNode.Length..]; Assert.True(payload.StartsWith(expectedUser)); } [Fact] public void ParseNormalHandshakeAck_WithNormalAckFrame_ReturnsAckData() { // Fixed vector for normal ACK assumption: // remaining=0x0006, type=0x0001, payload=0xA1B2C3, marker=0xA5. byte[] frame = [0x06, 0x00, 0x01, 0x00, 0xA1, 0xB2, 0xC3, 0xA5]; var ack = SuiteLinkHandshakeCodec.ParseNormalHandshakeAck(frame); Assert.Equal(0x0001, ack.MessageType); Assert.Equal(new byte[] { 0xA1, 0xB2, 0xC3 }, ack.Data.ToArray()); } [Fact] public void EncodeNormalQueryHandshake_WhenPayloadExceedsOneByteLength_ThrowsWithPayloadContext() { var ex = Assert.Throws(() => SuiteLinkHandshakeCodec.EncodeNormalQueryHandshake( targetApplication: "App", sourceNode: new string('N', 80), sourceUser: new string('U', 80))); Assert.Equal("payloadLength", ex.ParamName); Assert.Contains("Total handshake payload", ex.Message, StringComparison.OrdinalIgnoreCase); } }