public void IfCanSeekIsFalseLengthAndPositionShouldNotBeCalled() { var baseStream = new DelegateStream( canReadFunc: () => true, canSeekFunc: () => false, readFunc: (buffer, offset, count) => 0); var trackingStream = new CallTrackingStream(baseStream); var dest = Stream.Null; trackingStream.CopyTo(dest); var times = trackingStream.TimesCalled(nameof(trackingStream.CanSeek)); Assert.True(times >= 0 && times <= 1); Assert.AreEqual(0, trackingStream.TimesCalled(nameof(trackingStream.Length))); Assert.AreEqual(0, trackingStream.TimesCalled(nameof(trackingStream.Position))); // We can't override CopyTo since it's not virtual, so checking TimesCalled // for CopyTo will result in 0. Instead, we check that Read was called, // and validate the parameters passed there. Assert.AreEqual(1, trackingStream.TimesCalled(nameof(trackingStream.Read))); byte[] outerBuffer = trackingStream.ReadBuffer; int outerOffset = trackingStream.ReadOffset; int outerCount = trackingStream.ReadCount; Assert.NotNull(outerBuffer); Assert.True(outerOffset >= 0 && outerOffset <= (outerBuffer.Length - outerCount)); Assert.True(outerCount >= 1 && outerCount <= int.MaxValue); // the buffer can't be size 0 }
public void ShouldAlwaysFlushUnderlyingStreamIfWritable() { var data = new Tuple <bool, bool>[] { new Tuple <bool, bool>(true, true), new Tuple <bool, bool>(true, false), new Tuple <bool, bool>(false, true), new Tuple <bool, bool>(false, false) }; foreach (var item in data) { bool underlyingCanRead = item.Item1; bool underlyingCanSeek = item.Item2; var underlying = new DelegateStream ( canReadFunc: () => underlyingCanRead, canWriteFunc: () => true, canSeekFunc: () => underlyingCanSeek, readFunc: (_, __, ___) => 123, writeFunc: (_, __, ___) => { }, seekFunc: (_, __) => 123L ); var wrapper = new CallTrackingStream(underlying); var buffered = new BufferedStream(wrapper); buffered.Flush(); Assert.AreEqual(1, wrapper.TimesCalled(nameof(wrapper.Flush))); buffered.WriteByte(0); buffered.Flush(); Assert.AreEqual(2, wrapper.TimesCalled(nameof(wrapper.Flush))); } }
public void ShouldNotFlushUnderlyingStreamIfReadOnly() { var data = new bool[] { true, false }; foreach (var underlyingCanSeek in data) { var underlying = new DelegateStream( canReadFunc: () => true, canWriteFunc: () => false, canSeekFunc: () => underlyingCanSeek, readFunc: (_, __, ___) => 123, writeFunc: (_, __, ___) => { throw new NotSupportedException(); }, seekFunc: (_, __) => 123L ); var wrapper = new CallTrackingStream(underlying); var buffered = new BufferedStream(wrapper); buffered.ReadByte(); buffered.Flush(); Assert.AreEqual(0, wrapper.TimesCalled(nameof(wrapper.Flush))); } }
public void AsyncIfCanSeekIsFalseLengthAndPositionShouldNotBeCalled() { var baseStream = new DelegateStream( canReadFunc: () => true, canSeekFunc: () => false, readFunc: (buffer, offset, count) => 0); var trackingStream = new CallTrackingStream(baseStream); var dest = Stream.Null; trackingStream.CopyTo(dest); var times = trackingStream.TimesCalled(nameof(trackingStream.CanSeek)); Assert.True(times >= 0 && times <= 1); Assert.AreEqual(0, trackingStream.TimesCalled(nameof(trackingStream.Length))); Assert.AreEqual(0, trackingStream.TimesCalled(nameof(trackingStream.Position))); }
public void AsyncIfCanSeekIsTrueLengthAndPositionShouldOnlyBeCalledOnce() { var baseStream = new DelegateStream( canReadFunc: () => true, canSeekFunc: () => true, readFunc: (buffer, offset, count) => 0, lengthFunc: () => 0L, positionGetFunc: () => 0L); var trackingStream = new CallTrackingStream(baseStream); var dest = Stream.Null; trackingStream.CopyTo(dest); var times = trackingStream.TimesCalled(nameof(trackingStream.Length)); Assert.True(times >= 0 && times <= 1); times = trackingStream.TimesCalled(nameof(trackingStream.Position)); Assert.True(times >= 0 && times <= 1); }
public static void MemoryStream_CopyTo_Invalid() { MemoryStream memoryStream; using (memoryStream = new MemoryStream()) { Assert.Throws <ArgumentNullException>(() => memoryStream.CopyTo(destination: null)); // Validate the destination parameter first. Assert.Throws <ArgumentNullException>(() => memoryStream.CopyTo(destination: null, bufferSize: 0)); Assert.Throws <ArgumentNullException>(() => memoryStream.CopyTo(destination: null, bufferSize: -1)); // Then bufferSize. Assert.Throws <ArgumentOutOfRangeException>(() => memoryStream.CopyTo(Stream.Null, bufferSize: 0)); // 0-length buffer doesn't make sense. Assert.Throws <ArgumentOutOfRangeException>(() => memoryStream.CopyTo(Stream.Null, bufferSize: -1)); } // After the Stream is disposed, we should fail on all CopyTos. Assert.Throws <ArgumentOutOfRangeException>(() => memoryStream.CopyTo(Stream.Null, bufferSize: 0)); // Not before bufferSize is validated. Assert.Throws <ArgumentOutOfRangeException>(() => memoryStream.CopyTo(Stream.Null, bufferSize: -1)); MemoryStream disposedStream = memoryStream; // We should throw first for the source being disposed... Assert.Throws <Exception>(() => memoryStream.CopyTo(disposedStream, 1)); // Then for the destination being disposed. memoryStream = new MemoryStream(); Assert.Throws <Exception>(() => memoryStream.CopyTo(disposedStream, 1)); // Then we should check whether we can't read but can write, which isn't possible for non-subclassed MemoryStreams. // THen we should check whether the destination can read but can't write. var readOnlyStream = new DelegateStream( canReadFunc: () => true, canWriteFunc: () => false ); Assert.Throws <NotSupportedException>(() => memoryStream.CopyTo(readOnlyStream, 1)); }
public void IfLengthIsLessThanOrEqualToPositionCopyToShouldStillBeCalledWithAPositiveBufferSize() { var data = LengthIsLessThanOrEqualToPosition(); foreach (var item in data) { long length = (long)item[0]; long position = (long)item[1]; // Streams with their Lengths <= their Positions, e.g. // new MemoryStream { Position = 3 }.SetLength(1) // should still be called CopyTo{Async} on with a // bufferSize of at least 1. 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; trackingStream.CopyTo(dest); // CopyTo is not virtual, so we can't override it in // CallTrackingStream and record the arguments directly. // Instead, validate the arguments passed to Read. Assert.AreEqual(1, trackingStream.TimesCalled(nameof(trackingStream.Read))); byte[] outerBuffer = trackingStream.ReadBuffer; int outerOffset = trackingStream.ReadOffset; int outerCount = trackingStream.ReadCount; Assert.NotNull(outerBuffer); Assert.True(outerOffset >= 0 && outerOffset <= (outerBuffer.Length - outerCount)); Assert.True(outerCount >= 1 && outerCount <= int.MaxValue); } }
public void IfLengthMinusPositionPositiveOverflowsBufferSizeShouldStillBePositive() { var data = LengthMinusPositionPositiveOverflows(); foreach (var item in data) { long length = (long)item[0]; long position = (long)item[1]; // The new implementation of Stream.CopyTo calculates the bytes left // in the Stream by calling Length - Position. This can overflow to a // negative number, so this tests that if that happens we don't send // in a negative bufferSize. 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; trackingStream.CopyTo(dest); // CopyTo is not virtual, so we can't override it in // CallTrackingStream and record the arguments directly. // Instead, validate the arguments passed to Read. Assert.AreEqual(1, trackingStream.TimesCalled(nameof(trackingStream.Read))); byte[] outerBuffer = trackingStream.ReadBuffer; int outerOffset = trackingStream.ReadOffset; int outerCount = trackingStream.ReadCount; Assert.NotNull(outerBuffer); Assert.True(outerOffset >= 0 && outerOffset <= (outerBuffer.Length - outerCount)); Assert.True(outerCount >= 1 && outerCount <= int.MaxValue); } }
public void IfLengthIsGreaterThanPositionAndDoesNotOverflowEverythingShouldGoNormally() { const int ReadLimit = 7; var data = LengthIsGreaterThanPositionAndDoesNotOverflow(); foreach (var item in data) { long length = (long)item[0]; long position = (long)item[1]; // 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.True(offset >= 0 && offset <= (buffer.Length - count)); Assert.True(count >= 1 && count <= int.MaxValue); // CopyTo should always pass in the same buffer/offset/count if (outerBuffer != null) { Assert.AreDeepEqual(outerBuffer, buffer); } else { outerBuffer = buffer; } if (outerOffset != null) { Assert.AreEqual(outerOffset, offset); } else { outerOffset = offset; } if (outerCount != null) { Assert.AreEqual(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.AreDeepEqual(outerBuffer, buffer); Assert.AreEqual(outerOffset, offset); Assert.AreEqual(readsLeft, count); }); var dest = new CallTrackingStream(destBase); src.CopyTo(dest); Assert.AreEqual(ReadLimit, src.TimesCalled(nameof(src.Read))); Assert.AreEqual(ReadLimit - 1, dest.TimesCalled(nameof(dest.Write))); } }