예제 #1
0
        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
        }
예제 #2
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)));
            }
        }
예제 #3
0
        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)));
            }
        }
예제 #4
0
        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)));
        }
예제 #5
0
        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);
        }
예제 #6
0
        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));
        }
예제 #7
0
        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);
            }
        }
예제 #8
0
        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);
            }
        }
예제 #9
0
        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)));
            }
        }