|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections.Generic;
using System.Net.Http.HPack;
using Xunit;
namespace System.Net.Http.Unit.Tests.HPack
{
public class HPackIntegerTest
{
[Theory]
[MemberData(nameof(IntegerCodecExactSamples))]
public void HPack_IntegerEncode(int value, int bits, byte[] expectedResult)
{
Span<byte> actualResult = new byte[64];
bool success = IntegerEncoder.Encode(value, bits, actualResult, out int bytesWritten);
Assert.True(success);
Assert.Equal(expectedResult.Length, bytesWritten);
Assert.True(actualResult.Slice(0, bytesWritten).SequenceEqual(expectedResult));
}
[Theory]
[MemberData(nameof(IntegerCodecExactSamples))]
public void HPack_IntegerEncode_ShortBuffer(int value, int bits, byte[] expectedResult)
{
Span<byte> actualResult = new byte[expectedResult.Length - 1];
bool success = IntegerEncoder.Encode(value, bits, actualResult, out int bytesWritten);
Assert.False(success);
}
[Theory]
[MemberData(nameof(IntegerCodecExactSamples))]
public void HPack_IntegerDecode(int expectedResult, int bits, byte[] encoded)
{
IntegerDecoder integerDecoder = new IntegerDecoder();
bool finished = integerDecoder.BeginTryDecode(encoded[0], bits, out int actualResult);
int i = 1;
for (; !finished && i < encoded.Length; ++i)
{
finished = integerDecoder.TryDecode(encoded[i], out actualResult);
}
Assert.True(finished);
Assert.Equal(encoded.Length, i);
Assert.Equal(expectedResult, actualResult);
}
[Fact]
public void IntegerEncoderDecoderRoundtrips()
{
IntegerDecoder decoder = new IntegerDecoder();
Span<byte> integerBytes = stackalloc byte[5];
for (int i = 0; i < 2048; ++i)
{
for (int prefixLength = 1; prefixLength <= 8; ++prefixLength)
{
integerBytes.Clear();
Assert.True(IntegerEncoder.Encode(i, prefixLength, integerBytes, out int length));
bool decodeResult = decoder.BeginTryDecode(integerBytes[0], prefixLength, out int intResult);
for (int j = 1; j < length; j++)
{
Assert.False(decodeResult);
decodeResult = decoder.TryDecode(integerBytes[j], out intResult);
}
Assert.True(decodeResult);
Assert.Equal(i, intResult);
}
}
}
public static IEnumerable<object[]> IntegerCodecExactSamples()
{
yield return new object[] { 10, 5, new byte[] { 0x0A } };
yield return new object[] { 1337, 5, new byte[] { 0x1F, 0x9A, 0x0A } };
yield return new object[] { 42, 8, new byte[] { 0x2A } };
yield return new object[] { 7, 3, new byte[] { 0x7, 0x0 } };
yield return new object[] { int.MaxValue, 1, new byte[] { 0x01, 0xfe, 0xff, 0xff, 0xff, 0x07 } };
yield return new object[] { int.MaxValue, 8, new byte[] { 0xff, 0x80, 0xfe, 0xff, 0xff, 0x07 } };
}
[Theory]
[MemberData(nameof(IntegerData_OverMax))]
public void IntegerDecode_Throws_IfMaxExceeded(int prefixLength, byte[] octets)
{
var decoder = new IntegerDecoder();
var result = decoder.BeginTryDecode(octets[0], prefixLength, out var intResult);
for (var j = 1; j < octets.Length - 1; j++)
{
Assert.False(decoder.TryDecode(octets[j], out intResult));
}
Assert.Throws<HPackDecodingException>(() => decoder.TryDecode(octets[octets.Length - 1], out intResult));
}
public static TheoryData<int, byte[]> IntegerData_OverMax
{
get
{
var data = new TheoryData<int, byte[]>();
data.Add(1, new byte[] { 0x01, 0xff, 0xff, 0xff, 0xff, 0x07 }); // Int32.MaxValue + 1
data.Add(1, new byte[] { 0x01, 0xff, 0xff, 0xff, 0xff, 0x08 }); // MSB exceeds maximum
data.Add(1, new byte[] { 0x01, 0xff, 0xff, 0xff, 0xff, 0x80 }); // Undefined since continuation bit set
data.Add(7, new byte[] { 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x08 }); // 1 bit too large
data.Add(7, new byte[] { 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F });
data.Add(7, new byte[] { 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0x80 }); // A continuation byte (0x80) where the byte after it would be too large.
data.Add(7, new byte[] { 0x7F, 0xFF, 0x00 }); // Encoded with 1 byte too many.
data.Add(8, new byte[] { 0xff, 0x81, 0xfe, 0xff, 0xff, 0x07 }); // Int32.MaxValue + 1
data.Add(8, new byte[] { 0xff, 0x81, 0xfe, 0xff, 0xff, 0x08 }); // MSB exceeds maximum
data.Add(8, new byte[] { 0xff, 0x81, 0xfe, 0xff, 0xff, 0x80 }); // Undefined since continuation bit set
return data;
}
}
}
}
|