File: src\Shared\test\Shared.Tests\runtime\Http3\VariableLengthIntegerHelperTests.cs
Web Access
Project: src\src\Servers\Kestrel\Core\test\Microsoft.AspNetCore.Server.Kestrel.Core.Tests.csproj (Microsoft.AspNetCore.Server.Kestrel.Core.Tests)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Buffers;
using System.Net.Http;
using Xunit;
 
namespace Common.Tests.Tests.System.Net.aspnetcore.Http3
{
    public class VariableLengthIntegerHelperTests
    {
        [Fact]
        public void TryRead_FromReadOnlySpan_BufferEmpty()
        {
            ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>();
            bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan,
                out long value, out int bytesRead);
 
            Assert.False(isSuccess);
            Assert.Equal(0, value);
            Assert.Equal(0, bytesRead);
        }
 
        [Fact]
        public void TryRead_FromReadOnlySpan_BufferNotEmpty_InitialOneByteLengthMask()
        {
            ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(new byte[]
            {
                1
            });
            bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan,
                out long value, out int bytesRead);
 
            Assert.True(isSuccess);
            Assert.Equal(1, value);
            Assert.Equal(1, bytesRead);
        }
 
        [Fact]
        public void TryRead_FromReadOnlySpan_BufferNotEmpty_InitialTwoByteLengthMask_Buffer16BigEndian()
        {
            ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(new byte[]
            {
                64,
                1
            });
            bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan,
                out long value, out int bytesRead);
 
            Assert.True(isSuccess);
            Assert.Equal(1, value);
            Assert.Equal(2, bytesRead);
        }
 
        [Fact]
        public void TryRead_FromReadOnlySpan_BufferNotEmpty_InitialTwoByteLengthMask_BufferNot16BigEndian()
        {
            ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(new byte[]
            {
                64
            });
            bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan,
                out long value, out int bytesRead);
 
            Assert.False(isSuccess);
            Assert.Equal(0, value);
            Assert.Equal(0, bytesRead);
        }
 
        [Fact]
        public void TryRead_FromReadOnlySpan_BufferNotEmpty_InitialFourByteLengthMask_TryReadUInt32BigEndian()
        {
            ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(new byte[]
            {
                128,
                0,
                0,
                2
            });
            bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan,
                out long value, out int bytesRead);
 
            Assert.True(isSuccess);
            Assert.Equal(2, value);
            Assert.Equal(4, bytesRead);
        }
 
        [Fact]
        public void TryRead_FromReadOnlySpan_BufferNotEmpty_InitialFourByteLengthMask_TryReadNotUInt32BigEndian()
        {
            ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(new byte[]
            {
                128
            });
            bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan,
                out long value, out int bytesRead);
 
            Assert.False(isSuccess);
            Assert.Equal(0, value);
            Assert.Equal(0, bytesRead);
        }
 
        [Fact]
        public void TryRead_FromReadOnlySpan_BufferNotEmpty_InitialEightByteLengthMask_TryReadUInt64BigEndian()
        {
            ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(
                new byte[]
            {
                192, 0, 0, 0,
                0, 0, 0, 4
            });
            bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan,
                out long value, out int bytesRead);
 
            Assert.True(isSuccess);
            Assert.Equal(4, value);
            Assert.Equal(8, bytesRead);
        }
 
        [Fact]
        public void TryRead_FromReadOnlySpan_BufferNotEmpty_InitialEightByteLengthMask_TryReadNotUInt64BigEndian()
        {
            ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(new byte[]
            {
                192
            });
            bool isSuccess = VariableLengthIntegerHelper.TryRead(readOnlySpan,
                out long value, out int bytesRead);
 
            Assert.False(isSuccess);
            Assert.Equal(0, value);
            Assert.Equal(0, bytesRead);
        }
 
        [Fact]
        public void TryRead_FromSequenceReader_NotSegmentedSequence()
        {
            ReadOnlySequence<byte> readOnlySequence = new ReadOnlySequence<byte>(new byte[]
            {
                1
            });
            SequenceReader<byte> sequenceReader = new SequenceReader<byte>(readOnlySequence);
            bool isSuccess = VariableLengthIntegerHelper.TryRead(ref sequenceReader,
                out long value);
 
            Assert.True(isSuccess);
            Assert.Equal(1, value);
            Assert.Equal(1, sequenceReader.CurrentSpanIndex);
        }
 
        internal class MemorySegment<T> : ReadOnlySequenceSegment<T>
        {
            internal MemorySegment(ReadOnlyMemory<T> memory)
            {
                Memory = memory;
            }
 
            internal MemorySegment<T> Append(ReadOnlyMemory<T> memory)
            {
                var segment = new MemorySegment<T>(memory)
                {
                    RunningIndex = RunningIndex + Memory.Length
                };
 
                Next = segment;
 
                return segment;
            }
        }
 
        [Fact]
        public void TryRead_FromSequenceReader_InitialTwoByteLengthMask_SegmentedSequence()
        {
            MemorySegment<byte> memorySegment1 = new MemorySegment<byte>(new byte[] { 64 });
            MemorySegment<byte> memorySegment2 = memorySegment1.Append(new byte[] { 1 });
            ReadOnlySequence<byte> readOnlySequence = new ReadOnlySequence<byte>(
                memorySegment1, 0, memorySegment2, memorySegment2.Memory.Length);
            SequenceReader<byte> sequenceReader = new SequenceReader<byte>(readOnlySequence);
            bool isSuccess = VariableLengthIntegerHelper.TryRead(ref sequenceReader,
                out long value);
 
            Assert.True(isSuccess);
            Assert.Equal(1, value);
            Assert.Equal(1, sequenceReader.CurrentSpanIndex);
        }
 
        [Fact]
        public void TryRead_FromSequenceReader_InitialFourByteLengthMask_SegmentedSequence()
        {
            MemorySegment<byte> memorySegment1 = new MemorySegment<byte>(new byte[] { 192 });
            MemorySegment<byte> memorySegment2 = memorySegment1.Append(new byte[] { 0, 0, 0, 0, 0, 0, 2 });
            ReadOnlySequence<byte> readOnlySequence = new ReadOnlySequence<byte>(
                memorySegment1, 0, memorySegment2, memorySegment2.Memory.Length);
            SequenceReader<byte> sequenceReader = new SequenceReader<byte>(readOnlySequence);
            bool isSuccess = VariableLengthIntegerHelper.TryRead(ref sequenceReader,
                out long value);
 
            Assert.True(isSuccess);
            Assert.Equal(2, value);
            Assert.Equal(7, sequenceReader.CurrentSpanIndex);
        }
 
        [Fact]
        public void TryRead_FromSequenceReader_NotValidSegmentedSequence()
        {
            MemorySegment<byte> memorySegment1 = new MemorySegment<byte>(new byte[] { 192 });
            MemorySegment<byte> memorySegment2 = memorySegment1.Append(new byte[] { 0, 0, 0, 0, 0, 2 });
            ReadOnlySequence<byte> readOnlySequence = new ReadOnlySequence<byte>(
                memorySegment1, 0, memorySegment2, memorySegment2.Memory.Length);
            SequenceReader<byte> sequenceReader = new SequenceReader<byte>(readOnlySequence);
            bool isSuccess = VariableLengthIntegerHelper.TryRead(ref sequenceReader,
                out long value);
 
            Assert.False(isSuccess);
            Assert.Equal(0, value);
        }
 
        [Fact]
        public void GetInteger_ValidSegmentedSequence()
        {
            MemorySegment<byte> memorySegment1 = new MemorySegment<byte>(new byte[] { 192 });
            MemorySegment<byte> memorySegment2 = memorySegment1.Append(new byte[] { 0, 0, 0, 0, 0, 0, 2 });
            ReadOnlySequence<byte> readOnlySequence = new ReadOnlySequence<byte>(
                memorySegment1, 0, memorySegment2, memorySegment2.Memory.Length);
            long result = VariableLengthIntegerHelper.GetInteger(readOnlySequence,
                out SequencePosition consumed, out SequencePosition examined);
 
            Assert.Equal(2, result);
            Assert.Equal(7, consumed.GetInteger());
            Assert.Equal(7, examined.GetInteger());
        }
 
        [Fact]
        public void GetInteger_NotValidSegmentedSequence()
        {
            MemorySegment<byte> memorySegment1 = new MemorySegment<byte>(new byte[] { 192 });
            MemorySegment<byte> memorySegment2 = memorySegment1.Append(new byte[] { 0, 0, 0, 0, 0, 2 });
            ReadOnlySequence<byte> readOnlySequence = new ReadOnlySequence<byte>(
                memorySegment1, 0, memorySegment2, memorySegment2.Memory.Length);
            long result = VariableLengthIntegerHelper.GetInteger(readOnlySequence,
                out SequencePosition consumed, out SequencePosition examined);
 
            Assert.Equal(-1, result);
            Assert.Equal(0, consumed.GetInteger());
            Assert.Equal(6, examined.GetInteger());
        }
 
        [Fact]
        public void TryWrite_BufferEmpty()
        {
            Span<byte> span = new Span<byte>();
            long longToEncode = 1;
            bool isSuccess = VariableLengthIntegerHelper.TryWrite(span,
                longToEncode, out int bytesWritten);
 
            Assert.False(isSuccess);
            Assert.Equal(0, bytesWritten);
        }
 
        [Theory]
        [InlineData(0)]
        [InlineData(2)]
        [InlineData(63)]
        public void TryWrite_BufferNotEmpty_OneByteLimit(long longToEncode)
        {
            Span<byte> span = new Span<byte>(new byte[1]);
            bool isSuccess = VariableLengthIntegerHelper.TryWrite(span,
                longToEncode, out int bytesWritten);
 
            Assert.True(isSuccess);
            Assert.Equal(1, bytesWritten);
            Assert.Equal(longToEncode, span[0]);
        }
 
        [Theory]
        [InlineData(64, new byte[] { 64, 64 })]
        [InlineData(66, new byte[] { 64, 66 })]
        [InlineData(16383, new byte[] { 127, 255 })]
        public void TryWrite_BufferNotEmpty_TwoByteLimit(long longToEncode,
            byte[] expected)
        {
            Span<byte> span = new Span<byte>(new byte[2]);
            bool isSuccess = VariableLengthIntegerHelper.TryWrite(span,
                longToEncode, out int bytesWritten);
 
            Assert.True(isSuccess);
            Assert.Equal(2, bytesWritten);
            Assert.Equal(expected, span.ToArray());
        }
 
        [Fact]
        public void TryWrite_BufferNotSizedCorrectly_TwoByteLimit()
        {
            long longToEncode = 64;
            Span<byte> span = new Span<byte>(new byte[1]);
            bool isSuccess = VariableLengthIntegerHelper.TryWrite(span,
                longToEncode, out int bytesWritten);
 
            Assert.False(isSuccess);
            Assert.Equal(0, bytesWritten);
        }
 
        [Theory]
        [InlineData(16384, new byte[] {128, 0, 64, 0 })]
        [InlineData(16386, new byte[] { 128, 0, 64, 2 })]
        [InlineData(1073741823, new byte[] { 191, 255, 255, 255 })]
        public void TryWrite_BufferNotEmpty_FourByteLimit(long longToEncode,
            byte[] expected)
        {
            Span<byte> span = new Span<byte>(new byte[4]);
            bool isSuccess = VariableLengthIntegerHelper.TryWrite(span,
                longToEncode, out int bytesWritten);
 
            Assert.True(isSuccess);
            Assert.Equal(4, bytesWritten);
            Assert.Equal(expected, span.ToArray());
        }
 
        [Fact]
        public void TryWrite_BufferNotSizedCorrectly_FourByteLimit()
        {
            long longToEncode = 16384;
            Span<byte> span = new Span<byte>(new byte[1]);
            bool isSuccess = VariableLengthIntegerHelper.TryWrite(span,
                longToEncode, out int bytesWritten);
 
            Assert.False(isSuccess);
            Assert.Equal(0, bytesWritten);
        }
 
        [Theory]
        [InlineData(1073741824, new byte[] { 192, 0, 0, 0, 64, 0, 0, 0 })]
        [InlineData(1073741826, new byte[] { 192, 0, 0, 0, 64, 0, 0, 2 })]
        [InlineData(4611686018427387903, new byte[] { 255, 255, 255, 255, 255, 255, 255, 255 })]
        public void TryWrite_BufferNotEmpty_EightByteLimit(long longToEncode,
            byte[] expected)
        {
            Span<byte> span = new Span<byte>(new byte[8]);
            bool isSuccess = VariableLengthIntegerHelper.TryWrite(span,
                longToEncode, out int bytesWritten);
 
            Assert.True(isSuccess);
            Assert.Equal(8, bytesWritten);
            Assert.Equal(expected, span.ToArray());
        }
 
        [Fact]
        public void TryWrite_BufferNotSizedCorrectly_EightByteLimit()
        {
            long longToEncode = 1073741824;
            Span<byte> span = new Span<byte>(new byte[1]);
            bool isSuccess = VariableLengthIntegerHelper.TryWrite(span,
                longToEncode, out int bytesWritten);
 
            Assert.False(isSuccess);
            Assert.Equal(0, bytesWritten);
        }
 
        [Theory]
        [InlineData(1, 1)]
        [InlineData(64, 2)]
        [InlineData(16384, 4)]
        [InlineData(1073741824, 8)]
        public void GetByteCountTest(long longToEncode, int expectedLimit)
        {
            int result = VariableLengthIntegerHelper.GetByteCount(longToEncode);
 
            Assert.Equal(expectedLimit, result);
        }
    }
}