public async Task AccessingUnownedMemoryThrowsIfUsedAfterAdvance() { var stream = new CallbackStream(async(s, token) => { var sw = new StreamWriter(s); await sw.WriteAsync("Hello "); await sw.FlushAsync(); }); var channel = stream.AsReadableChannel(); var data = Memory <byte> .Empty; while (true) { var result = await channel.ReadAsync(); var buffer = result.Buffer; if (buffer.IsEmpty && result.IsCompleted) { // Done break; } data = buffer.First; channel.Advance(buffer.End); } Assert.Throws <ObjectDisposedException>(() => data.Span); }
public async Task CanConsumeLessDataThanProduced() { var stream = new CallbackStream(async(s, token) => { var sw = new StreamWriter(s); await sw.WriteAsync("Hello "); await sw.FlushAsync(); await sw.WriteAsync("World"); await sw.FlushAsync(); }); var channel = stream.AsReadableChannel(); int index = 0; var message = "Hello World"; while (true) { var result = await channel.ReadAsync(); var buffer = result.Buffer; if (buffer.IsEmpty && result.IsCompleted) { // Done break; } var ch = (char)buffer.First.Span[0]; Assert.Equal(message[index++], ch); channel.Advance(buffer.Start.Seek(1)); } Assert.Equal(message.Length, index); }
public async Task NotCallingAdvanceWillCauseReadToThrow() { var stream = new CallbackStream(async(s, token) => { var sw = new StreamWriter(s); await sw.WriteAsync("Hello"); await sw.FlushAsync(); await sw.WriteAsync("World"); await sw.FlushAsync(); }); var channel = stream.AsReadableChannel(); int calls = 0; InvalidOperationException thrown = null; while (true) { ChannelReadResult result; ReadableBuffer buffer; try { result = await channel.ReadAsync(); buffer = result.Buffer; } catch (InvalidOperationException ex) { thrown = ex; break; } calls++; if (buffer.IsEmpty && result.IsCompleted) { // Done break; } var segment = buffer.ToArray(); var data = Encoding.UTF8.GetString(segment); if (calls == 1) { Assert.Equal("Hello", data); } else { Assert.Equal("World", data); } } Assert.Equal(1, calls); Assert.NotNull(thrown); Assert.Equal("Cannot Read until the previous read has been acknowledged by calling Advance", thrown.Message); }
public async Task CanCancelConsumingData() { var cts = new CancellationTokenSource(); var stream = new CallbackStream(async(s, token) => { var hello = Encoding.UTF8.GetBytes("Hello"); var world = Encoding.UTF8.GetBytes("World"); await s.WriteAsync(hello, 0, hello.Length, token); cts.Cancel(); await s.WriteAsync(world, 0, world.Length, token); }); var channel = stream.AsReadableChannel(cts.Token); int calls = 0; while (true) { ChannelReadResult result; ReadableBuffer buffer; try { result = await channel.ReadAsync(); buffer = result.Buffer; } catch (OperationCanceledException) { break; } finally { calls++; } if (buffer.IsEmpty && result.IsCompleted) { // Done break; } var segment = buffer.ToArray(); var data = Encoding.UTF8.GetString(segment); Assert.Equal("Hello", data); channel.Advance(buffer.End); } Assert.Equal(2, calls); }
public async Task CanConsumeData() { var stream = new CallbackStream(async(s, token) => { var sw = new StreamWriter(s); await sw.WriteAsync("Hello"); await sw.FlushAsync(); await sw.WriteAsync("World"); await sw.FlushAsync(); }); var channel = stream.AsReadableChannel(); int calls = 0; while (true) { var result = await channel.ReadAsync(); var buffer = result.Buffer; calls++; if (buffer.IsEmpty && result.IsCompleted) { // Done break; } var segment = buffer.ToArray(); var data = Encoding.UTF8.GetString(segment); if (calls == 1) { Assert.Equal("Hello", data); } else { Assert.Equal("World", data); } channel.Advance(buffer.End); } }
public async Task PreservingUnownedBufferCopies() { var stream = new CallbackStream(async(s, token) => { var sw = new StreamWriter(s); await sw.WriteAsync("Hello "); await sw.FlushAsync(); }); var channel = stream.AsReadableChannel(); var preserved = default(PreservedBuffer); while (true) { var result = await channel.ReadAsync(); var buffer = result.Buffer; if (buffer.IsEmpty && result.IsCompleted) { // Done break; } preserved = buffer.Preserve(); // Make sure we can acccess the span var span = buffer.First.Span; channel.Advance(buffer.End); } using (preserved) { Assert.Equal("Hello ", Encoding.UTF8.GetString(preserved.Buffer.ToArray())); } Assert.Throws <ObjectDisposedException>(() => preserved.Buffer.First.Span); }
public async Task CanConsumeLessDataThanProducedWithBufferReuse() { var stream = new CallbackStream(async(s, token) => { var data = new byte[4096]; Encoding.UTF8.GetBytes("Hello ", 0, 6, data, 0); await s.WriteAsync(data, 0, 6); Encoding.UTF8.GetBytes("World", 0, 5, data, 0); await s.WriteAsync(data, 0, 5); }); var channel = stream.AsReadableChannel(); int index = 0; var message = "Hello World"; while (index <= message.Length) { var result = await channel.ReadAsync(); var buffer = result.Buffer; var ch = Encoding.UTF8.GetString(buffer.Slice(0, index).ToArray()); Assert.Equal(message.Substring(0, index), ch); // Never consume, to force buffers to be copied channel.Advance(buffer.Start, buffer.Start.Seek(index)); // Yield the task. This will ensure that we don't have any Tasks idling // around in UnownedBufferChannel.OnCompleted await Task.Yield(); index++; } Assert.Equal(message.Length + 1, index); }