public async Task AsyncIfLengthMinusPositionPositiveOverflowsBufferSizeShouldStillBePositive(long length, long position) { var baseStream = new DelegateStream( canReadFunc: () => true, canSeekFunc: () => true, lengthFunc: () => length, positionGetFunc: () => position, readFunc: (buffer, offset, count) => 0); var trackingStream = new CallTrackingStream(baseStream); var dest = Stream.Null; await trackingStream.CopyToAsync(dest); // Note: We can't check how many times ReadAsync was called // here, since trackingStream overrides CopyToAsync and forwards // to the inner (non-tracking) stream for the implementation Assert.Same(dest, trackingStream.CopyToAsyncDestination); Assert.InRange(trackingStream.CopyToAsyncBufferSize, 1, int.MaxValue); Assert.Equal(CancellationToken.None, trackingStream.CopyToAsyncCancellationToken); }
public void SetPositionInsideBufferRange_Read_WillNotReadUnderlyingStreamAgain(int sharedBufSize, Action <Stream, long> setPos) { var trackingStream = new CallTrackingStream(new MemoryStream()); var bufferedStream = new BufferedStream(trackingStream, sharedBufSize); bufferedStream.Write(Enumerable.Range(0, sharedBufSize * 2).Select(i => (byte)i).ToArray(), 0, sharedBufSize * 2); setPos(bufferedStream, 0); var readBuf = new byte[sharedBufSize - 1]; // First half part verification byte[] expectedReadBuf = Enumerable.Range(0, sharedBufSize - 1).Select(i => (byte)i).ToArray(); // Call Read() to fill shared read buffer int readBytes = bufferedStream.Read(readBuf, 0, readBuf.Length); Assert.Equal(readBuf.Length, readBytes); Assert.Equal(sharedBufSize - 1, bufferedStream.Position); Assert.Equal(expectedReadBuf, readBuf); Assert.Equal(1, trackingStream.TimesCalled(nameof(trackingStream.Read))); // Set position inside range of shared read buffer for (int pos = 0; pos < sharedBufSize - 1; pos++) { setPos(bufferedStream, pos); readBytes = bufferedStream.Read(readBuf, pos, readBuf.Length - pos); Assert.Equal(readBuf.Length - pos, readBytes); Assert.Equal(sharedBufSize - 1, bufferedStream.Position); Assert.Equal(expectedReadBuf, readBuf); // Should not trigger underlying stream's Read() Assert.Equal(1, trackingStream.TimesCalled(nameof(trackingStream.Read))); } Assert.Equal(sharedBufSize - 1, bufferedStream.ReadByte()); Assert.Equal(sharedBufSize, bufferedStream.Position); // Should not trigger underlying stream's Read() Assert.Equal(1, trackingStream.TimesCalled(nameof(trackingStream.Read))); // Second half part verification expectedReadBuf = Enumerable.Range(sharedBufSize, sharedBufSize - 1).Select(i => (byte)i).ToArray(); // Call Read() to fill shared read buffer readBytes = bufferedStream.Read(readBuf, 0, readBuf.Length); Assert.Equal(readBuf.Length, readBytes); Assert.Equal(sharedBufSize * 2 - 1, bufferedStream.Position); Assert.Equal(expectedReadBuf, readBuf); Assert.Equal(2, trackingStream.TimesCalled(nameof(trackingStream.Read))); // Set position inside range of shared read buffer for (int pos = 0; pos < sharedBufSize - 1; pos++) { setPos(bufferedStream, sharedBufSize + pos); readBytes = bufferedStream.Read(readBuf, pos, readBuf.Length - pos); Assert.Equal(readBuf.Length - pos, readBytes); Assert.Equal(sharedBufSize * 2 - 1, bufferedStream.Position); Assert.Equal(expectedReadBuf, readBuf); // Should not trigger underlying stream's Read() Assert.Equal(2, trackingStream.TimesCalled(nameof(trackingStream.Read))); } Assert.Equal(sharedBufSize * 2 - 1, bufferedStream.ReadByte()); Assert.Equal(sharedBufSize * 2, bufferedStream.Position); // Should not trigger underlying stream's Read() Assert.Equal(2, trackingStream.TimesCalled(nameof(trackingStream.Read))); }
public async void AsyncIfLengthIsGreaterThanPositionAndDoesNotOverflowEverythingShouldGoNormally(long length, long position) { const int ReadLimit = 7; // Lambda state byte[] outerBuffer = null; int? outerOffset = null; int? outerCount = null; int readsLeft = ReadLimit; var srcBase = new DelegateStream( canReadFunc: () => true, canSeekFunc: () => true, lengthFunc: () => length, positionGetFunc: () => position, readFunc: (buffer, offset, count) => { Assert.NotNull(buffer); Assert.InRange(offset, 0, buffer.Length - count); Assert.InRange(count, 1, int.MaxValue); // CopyTo should always pass in the same buffer/offset/count if (outerBuffer != null) { Assert.Same(outerBuffer, buffer); } else { outerBuffer = buffer; } if (outerOffset != null) { Assert.Equal(outerOffset, offset); } else { outerOffset = offset; } if (outerCount != null) { Assert.Equal(outerCount, count); } else { outerCount = count; } return(--readsLeft); // CopyTo will call Read on this ReadLimit times before stopping }); var src = new CallTrackingStream(srcBase); var destBase = new DelegateStream( canWriteFunc: () => true, writeFunc: (buffer, offset, count) => { Assert.Same(outerBuffer, buffer); Assert.Equal(outerOffset, offset); Assert.Equal(readsLeft, count); }); var dest = new CallTrackingStream(destBase); await src.CopyToAsync(dest); // Since we override CopyToAsync in CallTrackingStream, // src.Read will actually not get called ReadLimit // times, src.Inner.Read will. So, we just assert that // CopyToAsync was called once for src. Assert.Equal(1, src.TimesCalled(nameof(src.CopyToAsync))); Assert.Equal(ReadLimit - 1, dest.TimesCalled(nameof(dest.WriteAsync))); // dest.WriteAsync will still get called repeatedly }
public void IfLengthIsGreaterThanPositionAndDoesNotOverflowEverythingShouldGoNormally(long length, long position) { const int ReadLimit = 7; // Lambda state byte[] outerBuffer = null; int? outerOffset = null; int? outerCount = null; int readsLeft = ReadLimit; var srcBase = new DelegateStream( canReadFunc: () => true, canSeekFunc: () => true, lengthFunc: () => length, positionGetFunc: () => position, readFunc: (buffer, offset, count) => { Assert.NotNull(buffer); Assert.InRange(offset, 0, buffer.Length - count); Assert.InRange(count, 1, int.MaxValue); // CopyTo should always pass in the same buffer/offset/count if (outerBuffer != null) { Assert.Same(outerBuffer, buffer); } else { outerBuffer = buffer; } if (outerOffset != null) { Assert.Equal(outerOffset, offset); } else { outerOffset = offset; } if (outerCount != null) { Assert.Equal(outerCount, count); } else { outerCount = count; } return(--readsLeft); // CopyTo will call Read on this ReadLimit times before stopping }); var src = new CallTrackingStream(srcBase); var destBase = new DelegateStream( canWriteFunc: () => true, writeFunc: (buffer, offset, count) => { Assert.Same(outerBuffer, buffer); Assert.Equal(outerOffset, offset); Assert.Equal(readsLeft, count); }); var dest = new CallTrackingStream(destBase); src.CopyTo(dest); Assert.Equal(ReadLimit, src.TimesCalled(nameof(src.Read))); Assert.Equal(ReadLimit - 1, dest.TimesCalled(nameof(dest.Write))); }