150 lines
6.1 KiB
C#
150 lines
6.1 KiB
C#
using FinalFactory.Rendezvous.Contracts;
|
|
|
|
namespace FinalFactory.Rendezvous.Tests.Contracts;
|
|
|
|
public sealed class ContractLimitTests
|
|
{
|
|
[Fact]
|
|
public void RequiredPlayerFacingTextRejectsEmptyOrWhitespaceValues()
|
|
{
|
|
Assert.False(ContractValidation.IsBuildVersionValid(string.Empty));
|
|
Assert.False(ContractValidation.IsBuildVersionValid(" "));
|
|
Assert.False(ContractValidation.IsDisplayNameValid(string.Empty));
|
|
Assert.False(ContractValidation.IsDisplayNameValid(" "));
|
|
}
|
|
|
|
[Fact]
|
|
public void ByteAndCollectionLimitsAcceptTheBoundaryOnly()
|
|
{
|
|
Assert.True(ContractValidation.IsHttpRequestSizeValid(ContractLimits.HttpRequestMaxBytes));
|
|
Assert.False(ContractValidation.IsHttpRequestSizeValid(ContractLimits.HttpRequestMaxBytes + 1));
|
|
Assert.True(ContractValidation.IsBrowserResponseSizeValid(ContractLimits.BrowserResponseMaxBytes));
|
|
Assert.False(ContractValidation.IsBrowserResponseSizeValid(ContractLimits.BrowserResponseMaxBytes + 1));
|
|
Assert.True(ContractValidation.IsPageSizeValid(ContractLimits.BrowserPageMaxItems));
|
|
Assert.False(ContractValidation.IsPageSizeValid(ContractLimits.BrowserPageMaxItems + 1));
|
|
Assert.False(ContractValidation.IsPageSizeValid(0));
|
|
}
|
|
|
|
[Fact]
|
|
public void Utf8LimitsCountBytesInsteadOfCharacters()
|
|
{
|
|
string atLimit = new('é', ContractLimits.DisplayNameMaxBytes / 2);
|
|
string overLimit = atLimit + "é";
|
|
|
|
Assert.True(ContractValidation.IsDisplayNameValid(atLimit));
|
|
Assert.False(ContractValidation.IsDisplayNameValid(overLimit));
|
|
Assert.True(ContractValidation.IsBuildVersionValid(
|
|
new string('a', ContractLimits.BuildVersionMaxBytes)));
|
|
Assert.False(ContractValidation.IsBuildVersionValid(
|
|
new string('a', ContractLimits.BuildVersionMaxBytes + 1)));
|
|
}
|
|
|
|
[Fact]
|
|
public void CapabilityLimitStaysBelowLiteNetLibTokenLimit()
|
|
{
|
|
Assert.True(ContractValidation.IsCapabilityValid(
|
|
new string('a', ContractLimits.UdpCapabilityMaxCharacters - 1)));
|
|
Assert.True(ContractValidation.IsCapabilityValid(
|
|
new string('a', ContractLimits.UdpCapabilityMaxCharacters)));
|
|
Assert.False(ContractValidation.IsCapabilityValid(
|
|
new string('a', ContractLimits.UdpCapabilityMaxCharacters + 1)));
|
|
Assert.False(ContractValidation.IsCapabilityValid("not+base64url"));
|
|
Assert.True(
|
|
ContractLimits.UdpCapabilityMaxCharacters
|
|
< ContractLimits.LiteNetLibNatTokenMaxCharacters);
|
|
}
|
|
|
|
[Fact]
|
|
public void CapacityAndMetadataLimitsAreBounded()
|
|
{
|
|
Assert.True(ContractValidation.IsCapacityValid(new SessionCapacity
|
|
{
|
|
CurrentPlayers = ContractLimits.SessionCapacityMaxPlayers,
|
|
MaximumPlayers = ContractLimits.SessionCapacityMaxPlayers,
|
|
}));
|
|
Assert.False(ContractValidation.IsCapacityValid(new SessionCapacity
|
|
{
|
|
CurrentPlayers = 0,
|
|
MaximumPlayers = ContractLimits.SessionCapacityMaxPlayers + 1,
|
|
}));
|
|
|
|
Dictionary<string, string> maximumKeys = Enumerable
|
|
.Range(0, ContractLimits.MetadataMaxKeys)
|
|
.ToDictionary(index => $"key-{index}", _ => "value", StringComparer.Ordinal);
|
|
Dictionary<string, string> tooManyKeys = new(maximumKeys, StringComparer.Ordinal)
|
|
{
|
|
["overflow"] = "value",
|
|
};
|
|
|
|
Assert.True(ContractValidation.IsMetadataValid(maximumKeys));
|
|
Assert.False(ContractValidation.IsMetadataValid(tooManyKeys));
|
|
Assert.False(ContractValidation.IsMetadataValid(new Dictionary<string, string>
|
|
{
|
|
[new string('k', ContractLimits.MetadataKeyMaxBytes + 1)] = "value",
|
|
}));
|
|
Assert.False(ContractValidation.IsMetadataValid(new Dictionary<string, string>
|
|
{
|
|
["key"] = new string('v', ContractLimits.MetadataValueMaxBytes + 1),
|
|
}));
|
|
}
|
|
|
|
[Fact]
|
|
public void MetadataDocumentLimitAcceptsExactlyFourKibibytes()
|
|
{
|
|
Dictionary<string, string> atLimit = Enumerable
|
|
.Range(0, ContractLimits.MetadataMaxKeys)
|
|
.ToDictionary(index => $"k{index:00}", _ => string.Empty, StringComparer.Ordinal);
|
|
for (int index = 0; index < 14; index++)
|
|
{
|
|
atLimit[$"k{index:00}"] = new string('v', ContractLimits.MetadataValueMaxBytes);
|
|
}
|
|
|
|
atLimit["k14"] = new string('v', 223);
|
|
Dictionary<string, string> overLimit = new(atLimit, StringComparer.Ordinal)
|
|
{
|
|
["k14"] = new string('v', 224),
|
|
};
|
|
|
|
Assert.True(ContractValidation.IsMetadataValid(atLimit));
|
|
Assert.False(ContractValidation.IsMetadataValid(overLimit));
|
|
}
|
|
|
|
[Fact]
|
|
public void EndpointValidationIsAddressFamilyAware()
|
|
{
|
|
Assert.True(ContractValidation.IsNetworkEndpointValid(new NetworkEndpoint
|
|
{
|
|
AddressFamily = AddressFamilyKind.Ipv4,
|
|
Address = "192.0.2.10",
|
|
Port = 9050,
|
|
}));
|
|
Assert.True(ContractValidation.IsNetworkEndpointValid(new NetworkEndpoint
|
|
{
|
|
AddressFamily = AddressFamilyKind.Ipv6,
|
|
Address = "2001:db8::10",
|
|
Port = 9050,
|
|
}));
|
|
Assert.False(ContractValidation.IsNetworkEndpointValid(new NetworkEndpoint
|
|
{
|
|
AddressFamily = AddressFamilyKind.Ipv4,
|
|
Address = "2001:db8::10",
|
|
Port = 9050,
|
|
}));
|
|
}
|
|
|
|
[Fact]
|
|
public void ScopeAndOpaqueTextBoundariesAreEnforced()
|
|
{
|
|
Assert.True(GameId.TryParse(new string('a', ContractLimits.GameIdMaxCharacters), out _));
|
|
Assert.False(GameId.TryParse(
|
|
new string('a', ContractLimits.GameIdMaxCharacters + 1),
|
|
out _));
|
|
Assert.True(ContractValidation.IsIdempotencyKeyValid(
|
|
new string('i', ContractLimits.IdempotencyKeyMaxCharacters)));
|
|
Assert.False(ContractValidation.IsIdempotencyKeyValid(
|
|
new string('i', ContractLimits.IdempotencyKeyMaxCharacters + 1)));
|
|
Assert.True(ContractValidation.IsCursorValid(null));
|
|
Assert.False(ContractValidation.IsCursorValid("contains whitespace"));
|
|
}
|
|
}
|