|
7 | 7 | using System.Collections.Generic;
|
8 | 8 | using System.IO;
|
9 | 9 | using System.Text;
|
| 10 | +using System.Threading; |
10 | 11 | using System.Threading.Tasks;
|
11 | 12 | using Xunit;
|
12 | 13 |
|
@@ -55,6 +56,22 @@ public static async Task ReadToEndAsync()
|
55 | 56 | Assert.Equal(5000, result.Length);
|
56 | 57 | }
|
57 | 58 |
|
| 59 | + [Fact] |
| 60 | + public static async Task ReadToEndAsync_Reads_Asynchronously() |
| 61 | + { |
| 62 | + // Arrange |
| 63 | + var stream = new AsyncOnlyStreamWrapper(GetLargeStream()); |
| 64 | + var reader = new HttpRequestStreamReader(stream, Encoding.UTF8); |
| 65 | + var streamReader = new StreamReader(GetLargeStream()); |
| 66 | + string expected = await streamReader.ReadToEndAsync(); |
| 67 | + |
| 68 | + // Act |
| 69 | + var actual = await reader.ReadToEndAsync(); |
| 70 | + |
| 71 | + // Assert |
| 72 | + Assert.Equal(expected, actual); |
| 73 | + } |
| 74 | + |
58 | 75 | [Fact]
|
59 | 76 | public static void TestRead()
|
60 | 77 | {
|
@@ -477,5 +494,84 @@ public static IEnumerable<object[]> ReadLineData()
|
477 | 494 | httpRequestStreamReader.ReadLineAsync()
|
478 | 495 | )};
|
479 | 496 | }
|
| 497 | + |
| 498 | + private class AsyncOnlyStreamWrapper : Stream |
| 499 | + { |
| 500 | + private readonly Stream _inner; |
| 501 | + |
| 502 | + public AsyncOnlyStreamWrapper(Stream inner) |
| 503 | + { |
| 504 | + _inner = inner; |
| 505 | + } |
| 506 | + |
| 507 | + public override bool CanRead => _inner.CanRead; |
| 508 | + |
| 509 | + public override bool CanSeek => _inner.CanSeek; |
| 510 | + |
| 511 | + public override bool CanWrite => _inner.CanWrite; |
| 512 | + |
| 513 | + public override long Length => _inner.Length; |
| 514 | + |
| 515 | + public override long Position |
| 516 | + { |
| 517 | + get => _inner.Position; |
| 518 | + set => _inner.Position = value; |
| 519 | + } |
| 520 | + |
| 521 | + public override void Flush() |
| 522 | + { |
| 523 | + throw SyncOperationForbiddenException(); |
| 524 | + } |
| 525 | + |
| 526 | + public override Task FlushAsync(CancellationToken cancellationToken) |
| 527 | + { |
| 528 | + return _inner.FlushAsync(cancellationToken); |
| 529 | + } |
| 530 | + |
| 531 | + public override int Read(byte[] buffer, int offset, int count) |
| 532 | + { |
| 533 | + throw SyncOperationForbiddenException(); |
| 534 | + } |
| 535 | + |
| 536 | + public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) |
| 537 | + { |
| 538 | + return _inner.ReadAsync(buffer, offset, count, cancellationToken); |
| 539 | + } |
| 540 | + |
| 541 | + public override long Seek(long offset, SeekOrigin origin) |
| 542 | + { |
| 543 | + return _inner.Seek(offset, origin); |
| 544 | + } |
| 545 | + |
| 546 | + public override void SetLength(long value) |
| 547 | + { |
| 548 | + _inner.SetLength(value); |
| 549 | + } |
| 550 | + |
| 551 | + public override void Write(byte[] buffer, int offset, int count) |
| 552 | + { |
| 553 | + throw SyncOperationForbiddenException(); |
| 554 | + } |
| 555 | + |
| 556 | + public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) |
| 557 | + { |
| 558 | + return _inner.WriteAsync(buffer, offset, count, cancellationToken); |
| 559 | + } |
| 560 | + |
| 561 | + protected override void Dispose(bool disposing) |
| 562 | + { |
| 563 | + _inner.Dispose(); |
| 564 | + } |
| 565 | + |
| 566 | + public override ValueTask DisposeAsync() |
| 567 | + { |
| 568 | + return _inner.DisposeAsync(); |
| 569 | + } |
| 570 | + |
| 571 | + private Exception SyncOperationForbiddenException() |
| 572 | + { |
| 573 | + return new InvalidOperationException("The stream cannot be accessed synchronously"); |
| 574 | + } |
| 575 | + } |
480 | 576 | }
|
481 | 577 | }
|
0 commit comments