102 lines
3.9 KiB
C#
102 lines
3.9 KiB
C#
using FinalFactory.Rendezvous.Contracts;
|
|
|
|
namespace FinalFactory.Rendezvous.Tests.Contracts;
|
|
|
|
public sealed class UdpCodecTests
|
|
{
|
|
private static readonly Guid Handle = new("00112233-4455-6677-8899-aabbccddeeff");
|
|
|
|
[Fact]
|
|
public void HostPresenceMatchesTheV1GoldenVector()
|
|
{
|
|
byte[] encoded = RendezvousUdpCodec.Encode(CreateDatagram());
|
|
|
|
Assert.Equal(ContractTestFiles.Read("udp-host-ipv4.hex"), Convert.ToHexString(encoded).ToLowerInvariant());
|
|
Assert.True(RendezvousUdpCodec.TryDecode(encoded, out PresenceDatagram? decoded, out UdpDecodeError error));
|
|
Assert.Equal(UdpDecodeError.None, error);
|
|
Assert.NotNull(decoded);
|
|
Assert.Equal(Handle, decoded.MediationHandle.Value);
|
|
Assert.Equal("192.0.2.10", decoded.LocalAddress);
|
|
Assert.Equal(9050, decoded.LocalPort);
|
|
Assert.Equal("Abc_123-xYz", decoded.Capability);
|
|
}
|
|
|
|
[Fact]
|
|
public void Ipv6RoundtripsWithoutLosingItsAddressFamily()
|
|
{
|
|
PresenceDatagram original = CreateDatagram();
|
|
original.MessageType = UdpPresenceMessageType.ClientPresence;
|
|
original.AddressFamily = AddressFamilyKind.Ipv6;
|
|
original.LocalAddress = "2001:db8::10";
|
|
|
|
byte[] encoded = RendezvousUdpCodec.Encode(original);
|
|
|
|
Assert.True(RendezvousUdpCodec.TryDecode(encoded, out PresenceDatagram? decoded, out _));
|
|
Assert.NotNull(decoded);
|
|
Assert.Equal(AddressFamilyKind.Ipv6, decoded.AddressFamily);
|
|
Assert.Equal("2001:db8::10", decoded.LocalAddress);
|
|
}
|
|
|
|
[Fact]
|
|
public void EncoderRejectsAnAddressFamilyMismatch()
|
|
{
|
|
PresenceDatagram datagram = CreateDatagram();
|
|
datagram.AddressFamily = AddressFamilyKind.Ipv4;
|
|
datagram.LocalAddress = "2001:db8::10";
|
|
|
|
Assert.Throws<ArgumentException>(() => RendezvousUdpCodec.Encode(datagram));
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData(2, 2, UdpDecodeError.UnsupportedVersion)]
|
|
[InlineData(3, 3, UdpDecodeError.UnknownMessageType)]
|
|
[InlineData(4, 1, UdpDecodeError.InvalidFlags)]
|
|
[InlineData(21, 5, UdpDecodeError.InvalidAddressFamily)]
|
|
public void DecoderReturnsStableErrorsForUnknownHeaderValues(
|
|
int offset,
|
|
byte replacement,
|
|
UdpDecodeError expected)
|
|
{
|
|
byte[] encoded = RendezvousUdpCodec.Encode(CreateDatagram());
|
|
encoded[offset] = replacement;
|
|
|
|
Assert.False(RendezvousUdpCodec.TryDecode(encoded, out _, out UdpDecodeError actual));
|
|
Assert.Equal(expected, actual);
|
|
}
|
|
|
|
[Fact]
|
|
public void DecoderRejectsTruncationTrailingDataAndOversizedPackets()
|
|
{
|
|
byte[] encoded = RendezvousUdpCodec.Encode(CreateDatagram());
|
|
byte[] trailing = [.. encoded, 0];
|
|
byte[] oversized = new byte[ContractLimits.UdpDatagramMaxBytes + 1];
|
|
|
|
Assert.False(RendezvousUdpCodec.TryDecode(encoded.AsSpan(0, encoded.Length - 1), out _, out UdpDecodeError truncated));
|
|
Assert.Equal(UdpDecodeError.Truncated, truncated);
|
|
Assert.False(RendezvousUdpCodec.TryDecode(trailing, out _, out UdpDecodeError trailingError));
|
|
Assert.Equal(UdpDecodeError.TrailingData, trailingError);
|
|
Assert.False(RendezvousUdpCodec.TryDecode(oversized, out _, out UdpDecodeError oversizedError));
|
|
Assert.Equal(UdpDecodeError.DatagramTooLarge, oversizedError);
|
|
}
|
|
|
|
[Fact]
|
|
public void DecoderRejectsNonBase64UrlCapabilities()
|
|
{
|
|
byte[] encoded = RendezvousUdpCodec.Encode(CreateDatagram());
|
|
encoded[^1] = (byte)'+';
|
|
|
|
Assert.False(RendezvousUdpCodec.TryDecode(encoded, out _, out UdpDecodeError error));
|
|
Assert.Equal(UdpDecodeError.InvalidCapability, error);
|
|
}
|
|
|
|
private static PresenceDatagram CreateDatagram() => new()
|
|
{
|
|
MessageType = UdpPresenceMessageType.HostPresence,
|
|
MediationHandle = new MediationHandle(Handle),
|
|
AddressFamily = AddressFamilyKind.Ipv4,
|
|
LocalAddress = "192.0.2.10",
|
|
LocalPort = 9050,
|
|
Capability = "Abc_123-xYz",
|
|
};
|
|
}
|