aspnetcore/test/Kestrel.Core.Tests/BufferReaderTests.cs

301 lines
10 KiB
C#

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Xunit;
namespace System.Buffers.Tests
{
public abstract class ReadableBufferReaderFacts
{
public class Array : SingleSegment
{
public Array() : base(ReadOnlySequenceFactory.ArrayFactory) { }
internal Array(ReadOnlySequenceFactory factory) : base(factory) { }
}
public class OwnedMemory : SingleSegment
{
public OwnedMemory() : base(ReadOnlySequenceFactory.OwnedMemoryFactory) { }
}
public class Memory : SingleSegment
{
public Memory() : base(ReadOnlySequenceFactory.MemoryFactory) { }
}
public class SingleSegment : SegmentPerByte
{
public SingleSegment() : base(ReadOnlySequenceFactory.SingleSegmentFactory) { }
internal SingleSegment(ReadOnlySequenceFactory factory) : base(factory) { }
[Fact]
public void AdvanceSingleBufferSkipsBytes()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2, 3, 4, 5 }));
reader.Advance(2);
Assert.Equal(2, reader.CurrentSegmentIndex);
Assert.Equal(3, reader.CurrentSegment[reader.CurrentSegmentIndex]);
Assert.Equal(3, reader.Peek());
reader.Advance(2);
Assert.Equal(5, reader.Peek());
Assert.Equal(4, reader.CurrentSegmentIndex);
Assert.Equal(5, reader.CurrentSegment[reader.CurrentSegmentIndex]);
}
[Fact]
public void TakeReturnsByteAndMoves()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2 }));
Assert.Equal(0, reader.CurrentSegmentIndex);
Assert.Equal(1, reader.CurrentSegment[reader.CurrentSegmentIndex]);
Assert.Equal(1, reader.Read());
Assert.Equal(1, reader.CurrentSegmentIndex);
Assert.Equal(2, reader.CurrentSegment[reader.CurrentSegmentIndex]);
Assert.Equal(2, reader.Read());
Assert.Equal(-1, reader.Read());
}
}
public class SegmentPerByte : ReadableBufferReaderFacts
{
public SegmentPerByte() : base(ReadOnlySequenceFactory.SegmentPerByteFactory) { }
internal SegmentPerByte(ReadOnlySequenceFactory factory) : base(factory) { }
}
internal ReadOnlySequenceFactory Factory { get; }
internal ReadableBufferReaderFacts(ReadOnlySequenceFactory factory)
{
Factory = factory;
}
[Fact]
public void PeekReturnsByteWithoutMoving()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2 }));
Assert.Equal(1, reader.Peek());
Assert.Equal(1, reader.Peek());
}
[Fact]
public void CursorIsCorrectAtEnd()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2 }));
reader.Read();
reader.Read();
Assert.True(reader.End);
}
[Fact]
public void CursorIsCorrectWithEmptyLastBlock()
{
var first = new BufferSegment(new byte[] { 1, 2 });
var last = first.Append(new byte[4]);
var reader = new BufferReader(new ReadOnlySequence<byte>(first, 0, last, 0));
reader.Read();
reader.Read();
reader.Read();
Assert.Same(last, reader.Position.GetObject());
Assert.Equal(0, reader.Position.GetInteger());
Assert.True(reader.End);
}
[Fact]
public void PeekReturnsMinuOneByteInTheEnd()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2 }));
Assert.Equal(1, reader.Read());
Assert.Equal(2, reader.Read());
Assert.Equal(-1, reader.Peek());
}
[Fact]
public void AdvanceToEndThenPeekReturnsMinusOne()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2, 3, 4, 5 }));
reader.Advance(5);
Assert.True(reader.End);
Assert.Equal(-1, reader.Peek());
}
[Fact]
public void AdvancingPastLengthThrows()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { 1, 2, 3, 4, 5 }));
try
{
reader.Advance(6);
Assert.True(false);
}
catch (Exception ex)
{
Assert.True(ex is ArgumentOutOfRangeException);
}
}
[Fact]
public void CtorFindsFirstNonEmptySegment()
{
var buffer = Factory.CreateWithContent(new byte[] { 1 });
var reader = new BufferReader(buffer);
Assert.Equal(1, reader.Peek());
}
[Fact]
public void EmptySegmentsAreSkippedOnMoveNext()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2 });
var reader = new BufferReader(buffer);
Assert.Equal(1, reader.Peek());
reader.Advance(1);
Assert.Equal(2, reader.Peek());
}
[Fact]
public void PeekGoesToEndIfAllEmptySegments()
{
var buffer = Factory.CreateOfSize(0);
var reader = new BufferReader(buffer);
Assert.Equal(-1, reader.Peek());
Assert.True(reader.End);
}
[Fact]
public void AdvanceTraversesSegments()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2, 3 });
var reader = new BufferReader(buffer);
reader.Advance(2);
Assert.Equal(3, reader.CurrentSegment[reader.CurrentSegmentIndex]);
Assert.Equal(3, reader.Read());
}
[Fact]
public void AdvanceThrowsPastLengthMultipleSegments()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2, 3 });
var reader = new BufferReader(buffer);
try
{
reader.Advance(4);
Assert.True(false);
}
catch (Exception ex)
{
Assert.True(ex is ArgumentOutOfRangeException);
}
}
[Fact]
public void TakeTraversesSegments()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2, 3 });
var reader = new BufferReader(buffer);
Assert.Equal(1, reader.Read());
Assert.Equal(2, reader.Read());
Assert.Equal(3, reader.Read());
Assert.Equal(-1, reader.Read());
}
[Fact]
public void PeekTraversesSegments()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2 });
var reader = new BufferReader(buffer);
Assert.Equal(1, reader.CurrentSegment[reader.CurrentSegmentIndex]);
Assert.Equal(1, reader.Read());
Assert.Equal(2, reader.CurrentSegment[reader.CurrentSegmentIndex]);
Assert.Equal(2, reader.Peek());
Assert.Equal(2, reader.Read());
Assert.Equal(-1, reader.Peek());
Assert.Equal(-1, reader.Read());
}
[Fact]
public void PeekWorkesWithEmptySegments()
{
var buffer = Factory.CreateWithContent(new byte[] { 1 });
var reader = new BufferReader(buffer);
Assert.Equal(0, reader.CurrentSegmentIndex);
Assert.Equal(1, reader.CurrentSegment.Length);
Assert.Equal(1, reader.Peek());
Assert.Equal(1, reader.Read());
Assert.Equal(-1, reader.Peek());
Assert.Equal(-1, reader.Read());
}
[Fact]
public void WorkesWithEmptyBuffer()
{
var reader = new BufferReader(Factory.CreateWithContent(new byte[] { }));
Assert.Equal(0, reader.CurrentSegmentIndex);
Assert.Equal(0, reader.CurrentSegment.Length);
Assert.Equal(-1, reader.Peek());
Assert.Equal(-1, reader.Read());
}
[Theory]
[InlineData(0, false)]
[InlineData(5, false)]
[InlineData(10, false)]
[InlineData(11, true)]
[InlineData(12, true)]
[InlineData(15, true)]
public void ReturnsCorrectCursor(int takes, bool end)
{
var readableBuffer = Factory.CreateWithContent(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
var reader = new BufferReader(readableBuffer);
for (int i = 0; i < takes; i++)
{
reader.Read();
}
var expected = end ? new byte[] { } : readableBuffer.Slice((long)takes).ToArray();
Assert.Equal(expected, readableBuffer.Slice(reader.Position).ToArray());
}
[Fact]
public void SlicingBufferReturnsCorrectCursor()
{
var buffer = Factory.CreateWithContent(new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
var sliced = buffer.Slice(2L);
var reader = new BufferReader(sliced);
Assert.Equal(sliced.ToArray(), buffer.Slice(reader.Position).ToArray());
Assert.Equal(2, reader.Peek());
Assert.Equal(0, reader.CurrentSegmentIndex);
}
[Fact]
public void ReaderIndexIsCorrect()
{
var buffer = Factory.CreateWithContent(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
var reader = new BufferReader(buffer);
var counter = 1;
while (!reader.End)
{
var span = reader.CurrentSegment;
for (int i = reader.CurrentSegmentIndex; i < span.Length; i++)
{
Assert.Equal(counter++, reader.CurrentSegment[i]);
}
reader.Advance(span.Length);
}
Assert.Equal(buffer.Length, reader.ConsumedBytes);
}
}
}