using FinalFactory.Rendezvous.Contracts; namespace FinalFactory.Rendezvous.Tests.Contracts; public sealed class NatPunchRequestTokenCodecTests { [Theory] [InlineData(NatPunchPeerRole.HostPresence)] [InlineData(NatPunchPeerRole.Host)] [InlineData(NatPunchPeerRole.Client)] public void FixedSizeTokensRoundTripBelowLiteNetLibLimit(NatPunchPeerRole role) { MediationHandle handle = new(Guid.NewGuid()); const string capability = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; string encoded = NatPunchRequestTokenCodec.Encode(role, handle, capability); Assert.Equal(NatPunchRequestTokenCodec.EncodedLength, encoded.Length); Assert.True(encoded.Length <= ContractLimits.LiteNetLibNatTokenMaxCharacters); Assert.True(NatPunchRequestTokenCodec.TryDecode(encoded, out NatPunchRequestToken? decoded)); Assert.NotNull(decoded); Assert.Equal(role, decoded.Role); Assert.Equal(handle, decoded.MediationHandle); Assert.Equal(capability, decoded.Capability); Assert.DoesNotContain(capability, decoded.ToString(), StringComparison.Ordinal); } [Fact] public void MalformedAndNonCanonicalTokensAreRejected() { string valid = NatPunchRequestTokenCodec.Encode( NatPunchPeerRole.Client, new MediationHandle(Guid.Parse("00112233-4455-6677-8899-aabbccddeeff")), "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); string uppercaseHandle = valid[..6] + valid.Substring(6, 32).ToUpperInvariant() + valid[38..]; Assert.False(NatPunchRequestTokenCodec.TryDecode(null, out _)); Assert.False(NatPunchRequestTokenCodec.TryDecode(valid[..^1], out _)); Assert.False(NatPunchRequestTokenCodec.TryDecode("x" + valid[1..], out _)); Assert.False(NatPunchRequestTokenCodec.TryDecode(valid[..^1] + "x", out _)); Assert.False(NatPunchRequestTokenCodec.TryDecode(uppercaseHandle, out _)); Assert.Throws(() => NatPunchRequestTokenCodec.Encode( (NatPunchPeerRole)99, new MediationHandle(Guid.NewGuid()), "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")); } [Fact] public void FixedWireLengthHasADedicatedLiteNetSafeContractLimit() { Assert.Equal(192, ContractLimits.NatPunchRequestTokenCharacters); Assert.Equal( ContractLimits.NatPunchRequestTokenCharacters, NatPunchRequestTokenCodec.EncodedLength); Assert.True( ContractLimits.NatPunchRequestTokenCharacters <= ContractLimits.LiteNetLibNatTokenMaxCharacters); } }