未验证 提交 36f2dc25 编写于 作者: S Stephen Toub 提交者: GitHub

Fix a few Stream-related issues in System.Net.Http (#70731)

* Fix a few Stream-related issues in System.Net.Http

* Put back WriteTimeout

* Fix tests
上级 5713beac
......@@ -122,6 +122,16 @@ public override int EndRead(IAsyncResult asyncResult)
return _innerStream.EndRead(asyncResult);
}
public override void CopyTo(Stream destination, int bufferSize)
{
_innerStream.CopyTo(destination, bufferSize);
}
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
{
return _innerStream.CopyToAsync(destination, bufferSize, cancellationToken);
}
#endregion Read
#region Write
......@@ -175,11 +185,6 @@ public override void EndWrite(IAsyncResult asyncResult)
{
_innerStream.EndWrite(asyncResult);
}
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
{
return _innerStream.CopyToAsync(destination, bufferSize, cancellationToken);
}
#endregion Write
}
}
......@@ -159,6 +159,7 @@ public override void CopyTo(Stream destination, int bufferSize)
if (_content.Length > _position)
{
destination.Write(_content.Span.Slice(_position));
_position = _content.Length;
}
}
......@@ -166,9 +167,16 @@ public override Task CopyToAsync(Stream destination, int bufferSize, Cancellatio
{
ValidateCopyToArguments(destination, bufferSize);
EnsureNotClosed();
return _content.Length > _position ?
destination.WriteAsync(_content.Slice(_position), cancellationToken).AsTask() :
Task.CompletedTask;
if (_content.Length > _position)
{
ReadOnlyMemory<byte> content = _content.Slice(_position);
_position = _content.Length;
return destination.WriteAsync(content, cancellationToken).AsTask();
}
else
{
return Task.CompletedTask;
}
}
#endif
......
......@@ -399,10 +399,17 @@ protected async Task ValidateMisuseExceptionsAsync(Stream stream)
Assert.Throws<IOException>(() => { stream.Seek(-1, SeekOrigin.Begin); });
Assert.Throws<IOException>(() => { stream.Seek(-stream.Position - 1, SeekOrigin.Current); });
Assert.Throws<IOException>(() => { stream.Seek(-stream.Length - 1, SeekOrigin.End); });
Assert.Throws<ArgumentException>(() => { stream.Seek(0, (SeekOrigin)(-1)); });
Assert.Throws<ArgumentException>(() => { stream.Seek(0, (SeekOrigin)3); });
Assert.Throws<ArgumentException>(() => { stream.Seek(0, ~SeekOrigin.Begin); });
Assert.Throws<ArgumentOutOfRangeException>(() => { stream.SetLength(-1); });
Assert.ThrowsAny<ArgumentException>(() => { stream.Seek(0, (SeekOrigin)(-1)); });
Assert.ThrowsAny<ArgumentException>(() => { stream.Seek(0, (SeekOrigin)3); });
Assert.ThrowsAny<ArgumentException>(() => { stream.Seek(0, ~SeekOrigin.Begin); });
if (CanSetLength)
{
Assert.Throws<ArgumentOutOfRangeException>(() => { stream.SetLength(-1); });
}
else
{
Assert.Throws<NotSupportedException>(() => { stream.SetLength(0); });
}
}
else
{
......@@ -616,10 +623,11 @@ protected sealed unsafe class NativeMemoryManager : MemoryManager<byte>
private readonly int _length;
private IntPtr _ptr;
public int PinRefCount;
private readonly string _ctorStack = Environment.StackTrace;
public NativeMemoryManager(int length) => _ptr = Marshal.AllocHGlobal(_length = length);
~NativeMemoryManager() => Assert.False(true, $"{nameof(NativeMemoryManager)} being finalized");
~NativeMemoryManager() => Assert.False(true, $"{nameof(NativeMemoryManager)} being finalized. Created at {_ctorStack}");
public override Memory<byte> Memory => CreateMemory(_length);
......
......@@ -490,6 +490,12 @@ public override int Read(byte[] buffer, int offset, int count)
}
}
public override int ReadByte()
{
Span<byte> buffer = stackalloc byte[1];
return Read(buffer) == 1 ? buffer[0] : -1;
}
public override int Read(Span<byte> buffer)
{
if (buffer.Length == 0)
......@@ -632,6 +638,8 @@ public override long Seek(long offset, SeekOrigin origin)
public override long Length => _length;
public override void Flush() { }
public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public override void SetLength(long value) { throw new NotSupportedException(); }
public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); }
public override void Write(ReadOnlySpan<byte> buffer) { throw new NotSupportedException(); }
......
......@@ -138,60 +138,44 @@ private void PrepareContent()
private sealed class ReadOnlyStream : DelegatingStream
{
public override bool CanWrite
public ReadOnlyStream(Stream innerStream) : base(innerStream)
{
get { return false; }
}
public override int WriteTimeout
{
get { throw new NotSupportedException(SR.net_http_content_readonly_stream); }
set { throw new NotSupportedException(SR.net_http_content_readonly_stream); }
}
public override bool CanWrite => false;
public ReadOnlyStream(Stream innerStream)
: base(innerStream)
{
}
public override void Flush() { }
public override void Flush()
{
public override Task FlushAsync(CancellationToken cancellationToken) => Task.CompletedTask;
public override void SetLength(long value) =>
throw new NotSupportedException(SR.net_http_content_readonly_stream);
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) =>
throw new NotSupportedException(SR.net_http_content_readonly_stream);
}
public override void SetLength(long value)
{
public override void EndWrite(IAsyncResult asyncResult) =>
throw new NotSupportedException(SR.net_http_content_readonly_stream);
}
public override void Write(byte[] buffer, int offset, int count)
{
public override void Write(byte[] buffer, int offset, int count) =>
throw new NotSupportedException(SR.net_http_content_readonly_stream);
}
public override void Write(ReadOnlySpan<byte> buffer)
{
public override void Write(ReadOnlySpan<byte> buffer) =>
throw new NotSupportedException(SR.net_http_content_readonly_stream);
}
public override void WriteByte(byte value)
{
public override void WriteByte(byte value) =>
throw new NotSupportedException(SR.net_http_content_readonly_stream);
}
public override Task WriteAsync(byte[] buffer, int offset, int count, Threading.CancellationToken cancellationToken)
{
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) =>
throw new NotSupportedException(SR.net_http_content_readonly_stream);
}
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default)
{
public override ValueTask WriteAsync(ReadOnlyMemory<byte> buffer, CancellationToken cancellationToken = default) =>
throw new NotSupportedException(SR.net_http_content_readonly_stream);
public override int WriteTimeout
{
get => throw new InvalidOperationException(SR.net_http_content_readonly_stream);
set => throw new InvalidOperationException(SR.net_http_content_readonly_stream);
}
}
}
......
......@@ -4,14 +4,20 @@
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.IO.Tests;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace System.Net.Http.Functional.Tests
{
public class ReadOnlyMemoryContentTest
public class ReadOnlyMemoryContentTest : StandaloneStreamConformanceTests
{
protected override Task<Stream> CreateReadOnlyStreamCore(byte[]? initialData) => new ReadOnlyMemoryContent(initialData).ReadAsStreamAsync();
protected override Task<Stream> CreateWriteOnlyStreamCore(byte[]? initialData) => Task.FromResult<Stream>(null);
protected override Task<Stream> CreateReadWriteStreamCore(byte[]? initialData) => Task.FromResult<Stream>(null);
protected override bool CanSetLength => false;
public static IEnumerable<object[]> ContentLengthsAndUseArrays()
{
foreach (int length in new[] { 0, 1, 4096 })
......@@ -55,8 +61,8 @@ public static IEnumerable<object[]> UseArraysAndReadStreamAsync()
[MemberData(nameof(ContentLengthsAndUseArrays))]
public void ContentLength_LengthMatchesArrayLength(int contentLength, bool useArray)
{
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out _, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
{
Assert.Equal(contentLength, content.Headers.ContentLength);
}
......@@ -67,32 +73,30 @@ public void ContentLength_LengthMatchesArrayLength(int contentLength, bool useAr
public async Task ReadAsStreamAsync_TrivialMembersHaveExpectedValuesAndBehavior(bool useArray, bool readStreamAsync)
{
const int ContentLength = 42;
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out Memory<byte> memory, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
using (Stream stream = await content.ReadAsStreamAsync(readStreamAsync))
{
using (Stream stream = await content.ReadAsStreamAsync(readStreamAsync))
{
// property values
Assert.Equal(ContentLength, stream.Length);
Assert.Equal(0, stream.Position);
Assert.True(stream.CanRead);
Assert.True(stream.CanSeek);
Assert.False(stream.CanWrite);
// not supported
Assert.Throws<NotSupportedException>(() => stream.SetLength(12345));
Assert.Throws<NotSupportedException>(() => stream.WriteByte(0));
Assert.Throws<NotSupportedException>(() => stream.Write(new byte[1], 0, 1));
Assert.Throws<NotSupportedException>(() => stream.Write(new ReadOnlySpan<byte>(new byte[1])));
await Assert.ThrowsAsync<NotSupportedException>(async () => await stream.WriteAsync(new byte[1], 0, 1));
await Assert.ThrowsAsync<NotSupportedException>(async () => await stream.WriteAsync(new ReadOnlyMemory<byte>(new byte[1])));
// nops
stream.Flush();
await stream.FlushAsync();
}
// property values
Assert.Equal(ContentLength, stream.Length);
Assert.Equal(0, stream.Position);
Assert.True(stream.CanRead);
Assert.True(stream.CanSeek);
Assert.False(stream.CanWrite);
// not supported
Assert.Throws<NotSupportedException>(() => stream.SetLength(12345));
Assert.Throws<NotSupportedException>(() => stream.WriteByte(0));
Assert.Throws<NotSupportedException>(() => stream.Write(new byte[1], 0, 1));
Assert.Throws<NotSupportedException>(() => stream.Write(new ReadOnlySpan<byte>(new byte[1])));
await Assert.ThrowsAsync<NotSupportedException>(async () => await stream.WriteAsync(new byte[1], 0, 1));
await Assert.ThrowsAsync<NotSupportedException>(async () => await stream.WriteAsync(new ReadOnlyMemory<byte>(new byte[1])));
// nops
stream.Flush();
await stream.FlushAsync();
}
}
......@@ -101,61 +105,59 @@ public async Task ReadAsStreamAsync_TrivialMembersHaveExpectedValuesAndBehavior(
public async Task ReadAsStreamAsync_Seek(bool useArray, bool readStreamAsync)
{
const int ContentLength = 42;
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out Memory<byte> memory, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
using (Stream s = await content.ReadAsStreamAsync(readStreamAsync))
{
using (Stream s = await content.ReadAsStreamAsync(readStreamAsync))
foreach (int pos in new[] { 0, ContentLength / 2, ContentLength - 1 })
{
foreach (int pos in new[] { 0, ContentLength / 2, ContentLength - 1 })
{
s.Position = pos;
Assert.Equal(pos, s.Position);
Assert.Equal(memory.Span[pos], s.ReadByte());
}
foreach (int pos in new[] { 0, ContentLength / 2, ContentLength - 1 })
{
Assert.Equal(0, s.Seek(0, SeekOrigin.Begin));
Assert.Equal(memory.Span[0], s.ReadByte());
}
Assert.Equal(ContentLength, s.Seek(0, SeekOrigin.End));
Assert.Equal(s.Position, s.Length);
Assert.Equal(-1, s.ReadByte());
s.Position = pos;
Assert.Equal(pos, s.Position);
Assert.Equal(memory.Span[pos], s.ReadByte());
}
Assert.Equal(0, s.Seek(-ContentLength, SeekOrigin.End));
Assert.Equal(0, s.Position);
foreach (int pos in new[] { 0, ContentLength / 2, ContentLength - 1 })
{
Assert.Equal(0, s.Seek(0, SeekOrigin.Begin));
Assert.Equal(memory.Span[0], s.ReadByte());
s.Position = 0;
Assert.Equal(0, s.Seek(0, SeekOrigin.Current));
Assert.Equal(0, s.Position);
Assert.Equal(1, s.Seek(1, SeekOrigin.Current));
Assert.Equal(1, s.Position);
Assert.Equal(memory.Span[1], s.ReadByte());
Assert.Equal(2, s.Position);
Assert.Equal(3, s.Seek(1, SeekOrigin.Current));
Assert.Equal(1, s.Seek(-2, SeekOrigin.Current));
Assert.Equal(int.MaxValue, s.Seek(int.MaxValue, SeekOrigin.Begin));
Assert.Equal(int.MaxValue, s.Position);
Assert.Equal(int.MaxValue, s.Seek(0, SeekOrigin.Current));
Assert.Equal(int.MaxValue, s.Position);
Assert.Equal(int.MaxValue, s.Seek(int.MaxValue - ContentLength, SeekOrigin.End));
Assert.Equal(int.MaxValue, s.Position);
Assert.Equal(-1, s.ReadByte());
Assert.Equal(int.MaxValue, s.Position);
Assert.Throws<ArgumentOutOfRangeException>("value", () => s.Position = -1);
Assert.Throws<IOException>(() => s.Seek(-1, SeekOrigin.Begin));
AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => s.Position = (long)int.MaxValue + 1);
AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => s.Seek((long)int.MaxValue + 1, SeekOrigin.Begin));
Assert.ThrowsAny<ArgumentException>(() => s.Seek(0, (SeekOrigin)42));
}
Assert.Equal(ContentLength, s.Seek(0, SeekOrigin.End));
Assert.Equal(s.Position, s.Length);
Assert.Equal(-1, s.ReadByte());
Assert.Equal(0, s.Seek(-ContentLength, SeekOrigin.End));
Assert.Equal(0, s.Position);
Assert.Equal(memory.Span[0], s.ReadByte());
s.Position = 0;
Assert.Equal(0, s.Seek(0, SeekOrigin.Current));
Assert.Equal(0, s.Position);
Assert.Equal(1, s.Seek(1, SeekOrigin.Current));
Assert.Equal(1, s.Position);
Assert.Equal(memory.Span[1], s.ReadByte());
Assert.Equal(2, s.Position);
Assert.Equal(3, s.Seek(1, SeekOrigin.Current));
Assert.Equal(1, s.Seek(-2, SeekOrigin.Current));
Assert.Equal(int.MaxValue, s.Seek(int.MaxValue, SeekOrigin.Begin));
Assert.Equal(int.MaxValue, s.Position);
Assert.Equal(int.MaxValue, s.Seek(0, SeekOrigin.Current));
Assert.Equal(int.MaxValue, s.Position);
Assert.Equal(int.MaxValue, s.Seek(int.MaxValue - ContentLength, SeekOrigin.End));
Assert.Equal(int.MaxValue, s.Position);
Assert.Equal(-1, s.ReadByte());
Assert.Equal(int.MaxValue, s.Position);
Assert.Throws<ArgumentOutOfRangeException>("value", () => s.Position = -1);
Assert.Throws<IOException>(() => s.Seek(-1, SeekOrigin.Begin));
AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => s.Position = (long)int.MaxValue + 1);
AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => s.Seek((long)int.MaxValue + 1, SeekOrigin.Begin));
Assert.ThrowsAny<ArgumentException>(() => s.Seek(0, (SeekOrigin)42));
}
}
......@@ -163,20 +165,17 @@ public async Task ReadAsStreamAsync_Seek(bool useArray, bool readStreamAsync)
[MemberData(nameof(ContentLengthsAndUseArraysAndReadStreamAsync))]
public async Task ReadAsStreamAsync_ReadByte_MatchesInput(int contentLength, bool useArray, bool readStreamAsync)
{
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out Memory<byte> memory, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
using (Stream stream = await content.ReadAsStreamAsync(readStreamAsync))
{
using (Stream stream = await content.ReadAsStreamAsync(readStreamAsync))
for (int i = 0; i < contentLength; i++)
{
for (int i = 0; i < contentLength; i++)
{
Assert.Equal(memory.Span[i], stream.ReadByte());
Assert.Equal(i + 1, stream.Position);
}
Assert.Equal(-1, stream.ReadByte());
Assert.Equal(stream.Length, stream.Position);
Assert.Equal(memory.Span[i], stream.ReadByte());
Assert.Equal(i + 1, stream.Position);
}
Assert.Equal(-1, stream.ReadByte());
Assert.Equal(stream.Length, stream.Position);
}
}
......@@ -185,26 +184,24 @@ public async Task ReadAsStreamAsync_ReadByte_MatchesInput(int contentLength, boo
public async Task ReadAsStreamAsync_Read_InvalidArguments(bool useArray, bool readStreamAsync)
{
const int ContentLength = 42;
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out Memory<byte> memory, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
using (Stream stream = await content.ReadAsStreamAsync(readStreamAsync))
{
using (Stream stream = await content.ReadAsStreamAsync(readStreamAsync))
{
AssertExtensions.Throws<ArgumentNullException>("buffer", () => stream.Read(null, 0, 0));
AssertExtensions.Throws<ArgumentNullException>("buffer", () => { stream.ReadAsync(null, 0, 0); });
AssertExtensions.Throws<ArgumentNullException>("buffer", () => stream.Read(null, 0, 0));
AssertExtensions.Throws<ArgumentNullException>("buffer", () => { stream.ReadAsync(null, 0, 0); });
AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => stream.Read(new byte[1], -1, 1));
AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => stream.Read(new byte[1], -1, 1));
AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => stream.Read(new byte[1], -1, 1));
AssertExtensions.Throws<ArgumentOutOfRangeException>("offset", () => stream.Read(new byte[1], -1, 1));
AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => stream.Read(new byte[1], 0, -1));
AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => stream.Read(new byte[1], 0, -1));
AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => stream.Read(new byte[1], 0, -1));
AssertExtensions.Throws<ArgumentOutOfRangeException>("count", () => stream.Read(new byte[1], 0, -1));
Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 2, 0); });
Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 2, 0); });
Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 0, 2); });
Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 0, 2); });
}
Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 2, 0); });
Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 2, 0); });
Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 0, 2); });
Assert.ThrowsAny<ArgumentException>(() => { stream.ReadAsync(new byte[1], 0, 2); });
}
}
......@@ -233,8 +230,8 @@ public async Task ReadAsStreamAsync_ReadMultipleBytes_MatchesInput(int mode, boo
{
const int ContentLength = 1024;
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out Memory<byte> memory, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
{
var buffer = new byte[3];
......@@ -274,8 +271,8 @@ public async Task ReadAsStreamAsync_ReadWithCancelableToken_MatchesInput(bool us
{
const int ContentLength = 100;
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out Memory<byte> memory, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
{
var buffer = new byte[1];
var cts = new CancellationTokenSource();
......@@ -307,9 +304,8 @@ public async Task ReadAsStreamAsync_ReadWithCanceledToken_MatchesInput(bool useA
{
const int ContentLength = 2;
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out Memory<byte> memory, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
{
using (Stream stream = await content.ReadAsStreamAsync(readStreamAsync))
{
......@@ -324,10 +320,9 @@ public async Task ReadAsStreamAsync_ReadWithCanceledToken_MatchesInput(bool useA
[MemberData(nameof(ContentLengthsAndUseArrays))]
public async Task CopyToAsync_AllContentCopied(int contentLength, bool useArray)
{
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out Memory<byte> memory, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
{
var destination = new MemoryStream();
await content.CopyToAsync(destination);
......@@ -339,10 +334,9 @@ public async Task CopyToAsync_AllContentCopied(int contentLength, bool useArray)
[MemberData(nameof(ContentLengthsAndUseArraysAndReadStreamAsync))]
public async Task ReadAsStreamAsync_CopyTo_AllContentCopied(int contentLength, bool useArray, bool readStreamAsync)
{
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out Memory<byte> memory, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
{
var destination = new MemoryStream();
using (Stream s = await content.ReadAsStreamAsync(readStreamAsync))
{
......@@ -358,8 +352,8 @@ public async Task ReadAsStreamAsync_CopyTo_AllContentCopied(int contentLength, b
public async Task ReadAsStreamAsync_CopyTo_InvalidArguments(bool useArray, bool readStreamAsync)
{
const int ContentLength = 42;
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(ContentLength, useArray, out Memory<byte> memory, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
{
using (Stream s = await content.ReadAsStreamAsync(readStreamAsync))
{
......@@ -384,10 +378,9 @@ public async Task ReadAsStreamAsync_CopyTo_InvalidArguments(bool useArray, bool
[MemberData(nameof(ContentLengthsAndUseArraysAndReadStreamAsync))]
public async Task ReadAsStreamAsync_CopyToAsync_AllContentCopied(int contentLength, bool useArray, bool readStreamAsync)
{
Memory<byte> memory;
using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out memory, out IMemoryOwner<byte> memoryOwner))
using (ReadOnlyMemoryContent content = CreateContent(contentLength, useArray, out Memory<byte> memory, out IMemoryOwner<byte> memoryOwner))
using (memoryOwner)
{
var destination = new MemoryStream();
using (Stream s = await content.ReadAsStreamAsync(readStreamAsync))
{
......
......@@ -3,6 +3,7 @@
using System;
using System.IO;
using System.IO.Tests;
using System.Threading.Tasks;
using Xunit;
......@@ -10,31 +11,19 @@
namespace System.Net.Http.Functional.Tests
{
public class StreamContentTest
public class StreamContentTest : StandaloneStreamConformanceTests
{
private readonly ITestOutputHelper _output;
public StreamContentTest(ITestOutputHelper output)
{
_output = output;
}
protected override Task<Stream> CreateReadOnlyStreamCore(byte[]? initialData) => initialData is null ? Task.FromResult<Stream>(null) : new StreamContent(new MemoryStream(initialData)).ReadAsStreamAsync();
protected override Task<Stream> CreateWriteOnlyStreamCore(byte[]? initialData) => Task.FromResult<Stream>(null);
protected override Task<Stream> CreateReadWriteStreamCore(byte[]? initialData) => Task.FromResult<Stream>(null);
protected override bool CanSetLength => false;
[Fact]
public void Ctor_NullStream_ThrowsArgumentNullException()
public void Ctor_InvalidArguments_Throws()
{
Assert.Throws<ArgumentNullException>(() => new StreamContent(null));
}
[Fact]
public void Ctor_ZeroBufferSize_ThrowsArgumentOutOfRangeException()
{
Assert.Throws<ArgumentOutOfRangeException>(() => new StreamContent(new MemoryStream(), 0));
}
[Fact]
public void Ctor_NullStreamAndZeroBufferSize_ThrowsArgumentNullException()
{
Assert.Throws<ArgumentNullException>(() => new StreamContent(null, 0));
Assert.Throws<ArgumentOutOfRangeException>(() => new StreamContent(new MemoryStream(), 0));
}
[Fact]
......@@ -207,80 +196,6 @@ public async Task ContentReadStream_GetPropertyPartiallyConsumed_ReturnOriginalS
Assert.NotSame(source, stream);
}
[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task ContentReadStream_CheckResultProperties_ValuesRepresentReadOnlyStream(bool readStreamAsync)
{
byte[] data = new byte[10];
for (int i = 0; i < data.Length; i++)
{
data[i] = (byte)i;
}
var source = new MockStream(data);
var content = new StreamContent(source);
Stream contentReadStream = await content.ReadAsStreamAsync(readStreamAsync);
// The following checks verify that the stream returned passes all read-related properties to the
// underlying MockStream and throws when using write-related members.
Assert.False(contentReadStream.CanWrite);
Assert.True(contentReadStream.CanRead);
Assert.Equal(source.Length, contentReadStream.Length);
Assert.Equal(1, source.CanSeekCount);
_output.WriteLine(contentReadStream.CanSeek.ToString());
Assert.Equal(2, source.CanSeekCount);
contentReadStream.Position = 3; // No exception.
Assert.Equal(3, contentReadStream.Position);
byte byteOnIndex3 = (byte)contentReadStream.ReadByte();
Assert.Equal(data[3], byteOnIndex3);
byte[] byteOnIndex4 = new byte[1];
int result = await contentReadStream.ReadAsync(byteOnIndex4, 0, 1);
Assert.Equal(1, result);
Assert.Equal(data[4], byteOnIndex4[0]);
byte[] byteOnIndex5 = new byte[1];
Assert.Equal(1, contentReadStream.Read(byteOnIndex5, 0, 1));
Assert.Equal(data[5], byteOnIndex5[0]);
byte[] byteOnIndex6 = new byte[1];
Assert.Equal(1, contentReadStream.Read(new Span<byte>(byteOnIndex6, 0, 1)));
Assert.Equal(data[6], byteOnIndex6[0]);
contentReadStream.ReadTimeout = 123;
Assert.Equal(123, source.ReadTimeout);
Assert.Equal(123, contentReadStream.ReadTimeout);
Assert.Equal(0, source.CanTimeoutCount);
_output.WriteLine(contentReadStream.CanTimeout.ToString());
Assert.Equal(1, source.CanTimeoutCount);
Assert.Equal(0, source.SeekCount);
contentReadStream.Seek(0, SeekOrigin.Begin);
Assert.Equal(1, source.SeekCount);
Assert.Throws<NotSupportedException>(() => { contentReadStream.WriteTimeout = 5; });
Assert.Throws<NotSupportedException>(() => contentReadStream.WriteTimeout.ToString());
Assert.Throws<NotSupportedException>(() => contentReadStream.Flush());
Assert.Throws<NotSupportedException>(() => contentReadStream.SetLength(1));
Assert.Throws<NotSupportedException>(() => contentReadStream.Write(null, 0, 0));
Assert.Throws<NotSupportedException>(() => contentReadStream.Write(new Span<byte>(Array.Empty<byte>())));
Assert.Throws<NotSupportedException>(() => contentReadStream.WriteByte(1));
Assert.Equal(0, source.DisposeCount);
contentReadStream.Dispose();
Assert.Equal(1, source.DisposeCount);
}
#region Helper methods
private class MockStream : MemoryStream
{
private bool _canSeek;
......@@ -362,7 +277,5 @@ private void SetBufferSize(int count)
}
}
}
#endregion
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册