Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
353 changes: 352 additions & 1 deletion tests/csharp/TestCodec.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Runtime.InteropServices;
using StructFrame;
using StructFrame.SerializationTest;
using StructFrame.FrameHeaders;

namespace StructFrameTests
{
Expand Down Expand Up @@ -186,6 +187,356 @@ public static bool ValidateMessageBytes(byte[] msgData)
return valid;
}

/// <summary>
/// Calculate Fletcher-16 checksum
/// </summary>
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) */

/// <summary>
/// Basic + Default frame format helper
/// </summary>
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();
}

/// <summary>
/// Tiny + Minimal frame format helper
/// </summary>
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();
}

/// <summary>
/// Basic + Extended frame format helper
/// </summary>
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();
}

/// <summary>
/// Basic + Extended + Multi System Stream frame format helper
/// </summary>
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();
}

/// <summary>
/// Basic + Minimal frame format helper
/// </summary>
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();
}

/// <summary>
/// Tiny + Default frame format helper
/// </summary>
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();
}

/// <summary>
/// Test codec for encoding/decoding test messages with various frame formats
/// </summary>
public static class TestCodecHelpers
{
/// <summary>
/// Get the frame parser for a given format name or profile
/// </summary>
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions tests/csharp/TestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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");
Expand Down