diff --git a/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs b/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs index bc082b920cfb90..4b7db2f249e5a5 100644 --- a/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs +++ b/src/libraries/System.IO.Pipelines/tests/PipeWriterTests.cs @@ -361,19 +361,97 @@ public async Task GetMemoryFlushWithACompletedReaderNoops() Assert.Equal(0, Pipe.Writer.UnflushedBytes); } - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotBrowser), nameof(PlatformDetection.Is64BitProcess))] + [Fact] public void UnflushedBytes_HandlesLargeValues() { - PipeWriter writer = PipeWriter.Create(Stream.Null); int bufferSize = 10000; + using (SingleBufferMemoryPool pool = new(bufferSize)) + { + PipeWriter writer = PipeWriter.Create(Stream.Null, new StreamPipeWriterOptions(pool)); + + while (writer.UnflushedBytes >= 0 && writer.UnflushedBytes <= int.MaxValue) + { + writer.GetMemory(bufferSize); + writer.Advance(bufferSize); + } + + Assert.Equal(2147490000, writer.UnflushedBytes); + } + } + + internal class SingleBufferMemoryPool : MemoryPool + { + private readonly int _maxBufferSize; + private byte[] _buffer; + private bool _disposed; + + internal SingleBufferMemoryPool(int maxBufferSize) + { + _maxBufferSize = maxBufferSize; + _buffer = new byte[maxBufferSize]; + } + + public override int MaxBufferSize => _maxBufferSize; - while (writer.UnflushedBytes >= 0 && writer.UnflushedBytes <= int.MaxValue) + public override IMemoryOwner Rent(int minBufferSize = -1) { - writer.GetMemory(bufferSize); - writer.Advance(bufferSize); + if (minBufferSize > _maxBufferSize) + { + throw new ArgumentOutOfRangeException(nameof(minBufferSize), $"{nameof(minBufferSize)} should be less than {_maxBufferSize}"); + } + + return new BufferMemoryOwner(minBufferSize, _maxBufferSize, _buffer); } - Assert.Equal(2147490000, writer.UnflushedBytes); + protected override void Dispose(bool disposing) + { + if (!_disposed) + { + return; + } + + if (disposing) + { + _buffer = null; + } + + _disposed = true; + } + } + + internal class BufferMemoryOwner : MemoryManager + { + private int _minBufferSize; + private byte[] _buffer; + private bool _disposed; + + public BufferMemoryOwner(int minBufferSize, int maxBufferSize, byte[] buffer) + { + _minBufferSize = minBufferSize <= 0 ? maxBufferSize : minBufferSize; + _buffer = buffer; + } + + public override Span GetSpan() => new(_buffer, 0, _minBufferSize); + + public override Memory Memory => new(_buffer, 0, _minBufferSize); + + public override MemoryHandle Pin(int elementIndex = 0) => throw new NotImplementedException(); + public override void Unpin() => throw new NotImplementedException(); + + protected override void Dispose(bool disposing) + { + if (!_disposed) + { + return; + } + + if (disposing) + { + _buffer = null; + } + + _disposed = true; + } } } }