feat: bootstrap suitelink tag client codecs
This commit is contained in:
111
tests/SuiteLink.Client.Tests/Protocol/SuiteLinkEncodingTests.cs
Normal file
111
tests/SuiteLink.Client.Tests/Protocol/SuiteLinkEncodingTests.cs
Normal file
@@ -0,0 +1,111 @@
|
||||
using SuiteLink.Client.Protocol;
|
||||
|
||||
namespace SuiteLink.Client.Tests.Protocol;
|
||||
|
||||
public sealed class SuiteLinkEncodingTests
|
||||
{
|
||||
[Fact]
|
||||
public void EncodeLengthPrefixedUtf16_WithAsciiText_WritesCharacterCountAndUtf16Bytes()
|
||||
{
|
||||
var bytes = SuiteLinkEncoding.EncodeLengthPrefixedUtf16("AB");
|
||||
|
||||
Assert.Equal(new byte[] { 0x02, 0x41, 0x00, 0x42, 0x00 }, bytes);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DecodeNullTerminatedUtf16_ReadsStringAndConsumedBytes()
|
||||
{
|
||||
var buffer = new byte[] { 0x48, 0x00, 0x69, 0x00, 0x00, 0x00, 0x20, 0x00 };
|
||||
|
||||
var text = SuiteLinkEncoding.DecodeNullTerminatedUtf16(buffer, out var consumed);
|
||||
|
||||
Assert.Equal("Hi", text);
|
||||
Assert.Equal(6, consumed);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteAndReadUInt32LittleEndian_RoundTripsValue()
|
||||
{
|
||||
Span<byte> bytes = stackalloc byte[4];
|
||||
|
||||
SuiteLinkEncoding.WriteUInt32LittleEndian(bytes, 0x11223344);
|
||||
var value = SuiteLinkEncoding.ReadUInt32LittleEndian(bytes);
|
||||
|
||||
Assert.Equal((uint)0x11223344, value);
|
||||
Assert.Equal(new byte[] { 0x44, 0x33, 0x22, 0x11 }, bytes.ToArray());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FileTimeToUtcDateTime_ConvertsKnownEpochValue()
|
||||
{
|
||||
const long unixEpochFileTime = 116444736000000000L;
|
||||
|
||||
var value = SuiteLinkEncoding.FileTimeToUtcDateTime(unixEpochFileTime);
|
||||
|
||||
Assert.Equal(new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc), value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DecodeNullTerminatedUtf16_WithOddLength_ThrowsFormatException()
|
||||
{
|
||||
var buffer = new byte[] { 0x41, 0x00, 0x00 };
|
||||
|
||||
Assert.Throws<FormatException>(() => SuiteLinkEncoding.DecodeNullTerminatedUtf16(buffer, out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DecodeNullTerminatedUtf16_WithoutNullTerminator_ThrowsFormatException()
|
||||
{
|
||||
var buffer = new byte[] { 0x41, 0x00, 0x42, 0x00 };
|
||||
|
||||
Assert.Throws<FormatException>(() => SuiteLinkEncoding.DecodeNullTerminatedUtf16(buffer, out _));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EncodeLengthPrefixedUtf16_WhenInputIsTooLong_ThrowsArgumentOutOfRangeException()
|
||||
{
|
||||
var value = new string('A', 256);
|
||||
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => SuiteLinkEncoding.EncodeLengthPrefixedUtf16(value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EncodeLengthPrefixedUtf16_WithSurrogatePair_PrefixUsesUtf16CodeUnits()
|
||||
{
|
||||
var bytes = SuiteLinkEncoding.EncodeLengthPrefixedUtf16("A\U0001F600");
|
||||
|
||||
Assert.Equal(3, bytes[0]);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ReadUInt32LittleEndian_WhenInputIsTooShort_ThrowsFormatException()
|
||||
{
|
||||
var buffer = new byte[] { 0x01, 0x02, 0x03 };
|
||||
|
||||
Assert.Throws<FormatException>(() => SuiteLinkEncoding.ReadUInt32LittleEndian(buffer));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteAndReadSingleLittleEndian_RoundTripsNonTrivialValue()
|
||||
{
|
||||
Span<byte> bytes = stackalloc byte[4];
|
||||
const float expected = 123.4567f;
|
||||
|
||||
SuiteLinkEncoding.WriteSingleLittleEndian(bytes, expected);
|
||||
var value = SuiteLinkEncoding.ReadSingleLittleEndian(bytes);
|
||||
|
||||
Assert.Equal(expected, value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void WriteAndReadSingleLittleEndian_RoundTripsNaN()
|
||||
{
|
||||
Span<byte> bytes = stackalloc byte[4];
|
||||
var expected = float.NaN;
|
||||
|
||||
SuiteLinkEncoding.WriteSingleLittleEndian(bytes, expected);
|
||||
var value = SuiteLinkEncoding.ReadSingleLittleEndian(bytes);
|
||||
|
||||
Assert.True(float.IsNaN(value));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user