From 2e569fab5f52d83f413287d9910c12af717ae0d5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 01:50:21 +0000 Subject: [PATCH 1/3] Initial plan From bcaa1464fceba815960579c5675c0961b4fb7251 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 01:59:24 +0000 Subject: [PATCH 2/3] Add inline frame format helper classes to C# tests Co-authored-by: rijesha <7819200+rijesha@users.noreply.github.com> --- tests/csharp/TestCodec.cs | 361 ++++++++++++++++++++++++++++++++++++- tests/csharp/TestRunner.cs | 4 +- 2 files changed, 362 insertions(+), 3 deletions(-) diff --git a/tests/csharp/TestCodec.cs b/tests/csharp/TestCodec.cs index f4ee0133..e428ada8 100644 --- a/tests/csharp/TestCodec.cs +++ b/tests/csharp/TestCodec.cs @@ -5,6 +5,7 @@ using System.Runtime.InteropServices; using StructFrame; using StructFrame.SerializationTest; +using StructFrame.FrameHeaders; namespace StructFrameTests { @@ -186,6 +187,356 @@ public static bool ValidateMessageBytes(byte[] msgData) return valid; } + /// + /// Calculate Fletcher-16 checksum + /// + internal static (byte, byte) FletcherChecksum(byte[] buffer, int start, int length) + { + byte byte1 = 0; + byte byte2 = 0; + + for (int i = start; i < start + length; i++) + { + byte1 = (byte)((byte1 + buffer[i]) % 256); + byte2 = (byte)((byte2 + byte1) % 256); + } + + return (byte1, byte2); + } + } + + /* Minimal frame format helper classes (replacing frame_compat) */ + + /// + /// Basic + Default frame format helper + /// + class BasicDefault : FrameFormatBase + { + public override byte[] Encode(int msgId, byte[] msgData) + { + const int headerSize = 4; + const int footerSize = 2; + int totalSize = headerSize + msgData.Length + footerSize; + + if (msgData.Length > 255) + return new byte[0]; + + byte[] buffer = new byte[totalSize]; + buffer[0] = HeaderConstants.BASIC_START_BYTE; + buffer[1] = HeaderBasic.GetSecondStartByte(1); // DEFAULT = 1 + buffer[2] = (byte)msgData.Length; + buffer[3] = (byte)msgId; + Array.Copy(msgData, 0, buffer, headerSize, msgData.Length); + + var (ck1, ck2) = TestCodec.FletcherChecksum(buffer, 2, headerSize + msgData.Length - 2); + buffer[totalSize - 2] = ck1; + buffer[totalSize - 1] = ck2; + + return buffer; + } + + public override FrameParseResult ValidatePacket(byte[] data, int length) + { + var result = new FrameParseResult { Valid = false, MsgId = 0, MsgData = new byte[0], MsgSize = 0 }; + + if (length < 6 || data[0] != HeaderConstants.BASIC_START_BYTE || !HeaderBasic.IsSecondStartByte(data[1])) + return result; + + int msgLen = data[2]; + int msgId = data[3]; + int totalSize = 4 + msgLen + 2; + + if (length < totalSize) + return result; + + var (ck1, ck2) = TestCodec.FletcherChecksum(data, 2, 4 + msgLen - 2); + if (ck1 == data[totalSize - 2] && ck2 == data[totalSize - 1]) + { + result.Valid = true; + result.MsgId = msgId; + result.MsgSize = msgLen; + result.MsgData = new byte[msgLen]; + Array.Copy(data, 4, result.MsgData, 0, msgLen); + } + + return result; + } + + public override FrameParseResult ParseByte(byte b) => throw new NotImplementedException(); + public override void Reset() => throw new NotImplementedException(); + } + + /// + /// Tiny + Minimal frame format helper + /// + class TinyMinimal : FrameFormatBase + { + public override byte[] Encode(int msgId, byte[] msgData) + { + const int headerSize = 2; + int totalSize = headerSize + msgData.Length; + + byte[] buffer = new byte[totalSize]; + buffer[0] = HeaderTiny.GetStartByte(0); // MINIMAL = 0 + buffer[1] = (byte)msgId; + Array.Copy(msgData, 0, buffer, headerSize, msgData.Length); + + return buffer; + } + + public override FrameParseResult ValidatePacket(byte[] data, int length) + { + var result = new FrameParseResult { Valid = false, MsgId = 0, MsgData = new byte[0], MsgSize = 0 }; + + if (length < 2 || !HeaderTiny.IsStartByte(data[0])) + return result; + + int msgId = data[1]; + int msgLen = length - 2; + + result.Valid = true; + result.MsgId = msgId; + result.MsgSize = msgLen; + result.MsgData = new byte[msgLen]; + Array.Copy(data, 2, result.MsgData, 0, msgLen); + + return result; + } + + public override FrameParseResult ParseByte(byte b) => throw new NotImplementedException(); + public override void Reset() => throw new NotImplementedException(); + } + + /// + /// Basic + Extended frame format helper + /// + class BasicExtended : FrameFormatBase + { + public override byte[] Encode(int msgId, byte[] msgData) + { + const int headerSize = 6; + const int footerSize = 2; + int totalSize = headerSize + msgData.Length + footerSize; + + if (msgData.Length > 65535) + return new byte[0]; + + byte[] buffer = new byte[totalSize]; + buffer[0] = HeaderConstants.BASIC_START_BYTE; + buffer[1] = HeaderBasic.GetSecondStartByte(4); // EXTENDED = 4 + buffer[2] = (byte)(msgData.Length & 0xFF); + buffer[3] = (byte)((msgData.Length >> 8) & 0xFF); + buffer[4] = 0; // PKG_ID + buffer[5] = (byte)msgId; + Array.Copy(msgData, 0, buffer, headerSize, msgData.Length); + + var (ck1, ck2) = TestCodec.FletcherChecksum(buffer, 2, headerSize + msgData.Length - 2); + buffer[totalSize - 2] = ck1; + buffer[totalSize - 1] = ck2; + + return buffer; + } + + public override FrameParseResult ValidatePacket(byte[] data, int length) + { + var result = new FrameParseResult { Valid = false, MsgId = 0, MsgData = new byte[0], MsgSize = 0 }; + + if (length < 8 || data[0] != HeaderConstants.BASIC_START_BYTE || !HeaderBasic.IsSecondStartByte(data[1])) + return result; + + int msgLen = data[2] | (data[3] << 8); + int msgId = data[5]; + int totalSize = 6 + msgLen + 2; + + if (length < totalSize) + return result; + + var (ck1, ck2) = TestCodec.FletcherChecksum(data, 2, 6 + msgLen - 2); + if (ck1 == data[totalSize - 2] && ck2 == data[totalSize - 1]) + { + result.Valid = true; + result.MsgId = msgId; + result.MsgSize = msgLen; + result.MsgData = new byte[msgLen]; + Array.Copy(data, 6, result.MsgData, 0, msgLen); + } + + return result; + } + + public override FrameParseResult ParseByte(byte b) => throw new NotImplementedException(); + public override void Reset() => throw new NotImplementedException(); + } + + /// + /// Basic + Extended + Multi System Stream frame format helper + /// + class BasicExtendedMultiSystemStream : FrameFormatBase + { + public override byte[] Encode(int msgId, byte[] msgData) + { + const int headerSize = 9; + const int footerSize = 2; + int totalSize = headerSize + msgData.Length + footerSize; + + if (msgData.Length > 65535) + return new byte[0]; + + byte[] buffer = new byte[totalSize]; + buffer[0] = HeaderConstants.BASIC_START_BYTE; + buffer[1] = HeaderBasic.GetSecondStartByte(8); // EXTENDED_MULTI_SYSTEM_STREAM = 8 + buffer[2] = 0; // SEQ + buffer[3] = 0; // SYS_ID + buffer[4] = 0; // COMP_ID + buffer[5] = (byte)(msgData.Length & 0xFF); + buffer[6] = (byte)((msgData.Length >> 8) & 0xFF); + buffer[7] = 0; // PKG_ID + buffer[8] = (byte)msgId; + Array.Copy(msgData, 0, buffer, headerSize, msgData.Length); + + var (ck1, ck2) = TestCodec.FletcherChecksum(buffer, 2, headerSize + msgData.Length - 2); + buffer[totalSize - 2] = ck1; + buffer[totalSize - 1] = ck2; + + return buffer; + } + + public override FrameParseResult ValidatePacket(byte[] data, int length) + { + var result = new FrameParseResult { Valid = false, MsgId = 0, MsgData = new byte[0], MsgSize = 0 }; + + if (length < 11 || data[0] != HeaderConstants.BASIC_START_BYTE || !HeaderBasic.IsSecondStartByte(data[1])) + return result; + + int msgLen = data[5] | (data[6] << 8); + int msgId = data[8]; + int totalSize = 9 + msgLen + 2; + + if (length < totalSize) + return result; + + var (ck1, ck2) = TestCodec.FletcherChecksum(data, 2, 9 + msgLen - 2); + if (ck1 == data[totalSize - 2] && ck2 == data[totalSize - 1]) + { + result.Valid = true; + result.MsgId = msgId; + result.MsgSize = msgLen; + result.MsgData = new byte[msgLen]; + Array.Copy(data, 9, result.MsgData, 0, msgLen); + } + + return result; + } + + public override FrameParseResult ParseByte(byte b) => throw new NotImplementedException(); + public override void Reset() => throw new NotImplementedException(); + } + + /// + /// Basic + Minimal frame format helper + /// + class BasicMinimal : FrameFormatBase + { + public override byte[] Encode(int msgId, byte[] msgData) + { + const int headerSize = 3; + int totalSize = headerSize + msgData.Length; + + byte[] buffer = new byte[totalSize]; + buffer[0] = HeaderConstants.BASIC_START_BYTE; + buffer[1] = HeaderBasic.GetSecondStartByte(0); // MINIMAL = 0 + buffer[2] = (byte)msgId; + Array.Copy(msgData, 0, buffer, headerSize, msgData.Length); + + return buffer; + } + + public override FrameParseResult ValidatePacket(byte[] data, int length) + { + var result = new FrameParseResult { Valid = false, MsgId = 0, MsgData = new byte[0], MsgSize = 0 }; + + if (length < 3 || data[0] != HeaderConstants.BASIC_START_BYTE || !HeaderBasic.IsSecondStartByte(data[1])) + return result; + + int msgId = data[2]; + int msgLen = length - 3; + + result.Valid = true; + result.MsgId = msgId; + result.MsgSize = msgLen; + result.MsgData = new byte[msgLen]; + Array.Copy(data, 3, result.MsgData, 0, msgLen); + + return result; + } + + public override FrameParseResult ParseByte(byte b) => throw new NotImplementedException(); + public override void Reset() => throw new NotImplementedException(); + } + + /// + /// Tiny + Default frame format helper + /// + class TinyDefault : FrameFormatBase + { + public override byte[] Encode(int msgId, byte[] msgData) + { + const int headerSize = 3; + const int footerSize = 2; + int totalSize = headerSize + msgData.Length + footerSize; + + if (msgData.Length > 255) + return new byte[0]; + + byte[] buffer = new byte[totalSize]; + buffer[0] = HeaderTiny.GetStartByte(1); // DEFAULT = 1 + buffer[1] = (byte)msgData.Length; + buffer[2] = (byte)msgId; + Array.Copy(msgData, 0, buffer, headerSize, msgData.Length); + + var (ck1, ck2) = TestCodec.FletcherChecksum(buffer, 1, headerSize + msgData.Length - 1); + buffer[totalSize - 2] = ck1; + buffer[totalSize - 1] = ck2; + + return buffer; + } + + public override FrameParseResult ValidatePacket(byte[] data, int length) + { + var result = new FrameParseResult { Valid = false, MsgId = 0, MsgData = new byte[0], MsgSize = 0 }; + + if (length < 5 || !HeaderTiny.IsStartByte(data[0])) + return result; + + int msgLen = data[1]; + int msgId = data[2]; + int totalSize = 3 + msgLen + 2; + + if (length < totalSize) + return result; + + var (ck1, ck2) = TestCodec.FletcherChecksum(data, 1, 3 + msgLen - 1); + if (ck1 == data[totalSize - 2] && ck2 == data[totalSize - 1]) + { + result.Valid = true; + result.MsgId = msgId; + result.MsgSize = msgLen; + result.MsgData = new byte[msgLen]; + Array.Copy(data, 3, result.MsgData, 0, msgLen); + } + + return result; + } + + public override FrameParseResult ParseByte(byte b) => throw new NotImplementedException(); + public override void Reset() => throw new NotImplementedException(); + } + + /// + /// Test codec for encoding/decoding test messages with various frame formats + /// + public static class TestCodecHelpers + { /// /// Get the frame parser for a given format name or profile /// @@ -222,7 +573,7 @@ public static FrameFormatBase GetParser(string formatName) public static byte[] EncodeTestMessage(string formatName) { var parser = GetParser(formatName); - byte[] msgData = CreateTestMessageBytes(); + byte[] msgData = TestCodec.CreateTestMessageBytes(); // Use MsgId from the generated struct definition return parser.Encode(SerializationTestSerializationTestMessage.MsgId, msgData); @@ -244,5 +595,13 @@ public static byte[] DecodeTestMessage(string formatName, byte[] data) return result.MsgData; } + + /// + /// Create serialized test message bytes with expected values + /// + private static byte[] CreateTestMessageBytes() + { + return TestCodec.CreateTestMessageBytes(); + } } } diff --git a/tests/csharp/TestRunner.cs b/tests/csharp/TestRunner.cs index df9aeb4b..f21dd69f 100644 --- a/tests/csharp/TestRunner.cs +++ b/tests/csharp/TestRunner.cs @@ -37,7 +37,7 @@ static int RunEncode(string formatName, string outputFile) byte[] encodedData; try { - encodedData = TestCodec.EncodeTestMessage(formatName); + encodedData = TestCodecHelpers.EncodeTestMessage(formatName); } catch (Exception e) { @@ -80,7 +80,7 @@ static int RunDecode(string formatName, string inputFile) return 1; } - var msgData = TestCodec.DecodeTestMessage(formatName, data); + var msgData = TestCodecHelpers.DecodeTestMessage(formatName, data); if (msgData == null) { Console.WriteLine("[DECODE] FAILED: Frame validation failed"); From 999cf2be1bded07b339f293ece385dfadcfff813 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 20 Dec 2025 02:00:58 +0000 Subject: [PATCH 3/3] Remove unnecessary wrapper method in TestCodecHelpers Co-authored-by: rijesha <7819200+rijesha@users.noreply.github.com> --- tests/csharp/TestCodec.cs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/csharp/TestCodec.cs b/tests/csharp/TestCodec.cs index e428ada8..191e31f1 100644 --- a/tests/csharp/TestCodec.cs +++ b/tests/csharp/TestCodec.cs @@ -595,13 +595,5 @@ public static byte[] DecodeTestMessage(string formatName, byte[] data) return result.MsgData; } - - /// - /// Create serialized test message bytes with expected values - /// - private static byte[] CreateTestMessageBytes() - { - return TestCodec.CreateTestMessageBytes(); - } } }