diff options
author | Stephen Toub <stoub@microsoft.com> | 2017-10-26 02:43:10 +0300 |
---|---|---|
committer | Stephen Toub <stoub@microsoft.com> | 2017-10-26 02:45:04 +0300 |
commit | 283af038c1c09b324e76acc8bb2c8a447b6664e6 (patch) | |
tree | e197da97a3a8a57dd011c8e89eb2004e3cda5958 /src | |
parent | 0558ff46df30b93b22d7567d2f58f9b1755df7cd (diff) |
Boost code coverage
And a few minor resulting fixes.
Diffstat (limited to 'src')
5 files changed, 100 insertions, 22 deletions
diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/Channel.cs b/src/System.Threading.Channels/src/System/Threading/Channels/Channel.cs index 9dedd4ef9f..ed1b3f34ef 100644 --- a/src/System.Threading.Channels/src/System/Threading/Channels/Channel.cs +++ b/src/System.Threading.Channels/src/System/Threading/Channels/Channel.cs @@ -17,7 +17,7 @@ namespace System.Threading.Channels /// <param name="options">Options that guide the behavior of the channel.</param> /// <returns>The created channel.</returns> public static Channel<T> CreateUnbounded<T>(UnboundedChannelOptions options) => - options == null ? throw new ArgumentOutOfRangeException(nameof(options)) : + options == null ? throw new ArgumentNullException(nameof(options)) : options.SingleReader ? new SingleConsumerUnboundedChannel<T>(!options.AllowSynchronousContinuations) : (Channel<T>)new UnboundedChannel<T>(!options.AllowSynchronousContinuations); @@ -47,7 +47,7 @@ namespace System.Threading.Channels { if (options == null) { - throw new ArgumentOutOfRangeException(nameof(options)); + throw new ArgumentNullException(nameof(options)); } return new BoundedChannel<T>(options.Capacity, options.FullMode, !options.AllowSynchronousContinuations); @@ -67,7 +67,7 @@ namespace System.Threading.Channels { if (options == null) { - throw new ArgumentOutOfRangeException(nameof(options)); + throw new ArgumentNullException(nameof(options)); } return new UnbufferedChannel<T>(); diff --git a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelUtilities.cs b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelUtilities.cs index a7411c4fb2..07995d5659 100644 --- a/src/System.Threading.Channels/src/System/Threading/Channels/ChannelUtilities.cs +++ b/src/System.Threading.Channels/src/System/Threading/Channels/ChannelUtilities.cs @@ -44,22 +44,6 @@ namespace System.Threading.Channels } } - /// <summary>Gets a value task representing an error.</summary> - /// <typeparam name="T">Specifies the type of the value that would have been returned.</typeparam> - /// <param name="error">The error. This may be <see cref="s_doneWritingSentinel"/>.</param> - /// <returns>The failed task.</returns> - internal static ValueTask<T> GetInvalidCompletionValueTask<T>(Exception error) - { - Debug.Assert(error != null); - - Task<T> t = - error == s_doneWritingSentinel ? Task.FromException<T>(CreateInvalidCompletionException()) : - error is OperationCanceledException oce ? Task.FromCanceled<T>(oce.CancellationToken.IsCancellationRequested ? oce.CancellationToken : new CancellationToken(true)) : - Task.FromException<T>(CreateInvalidCompletionException(error)); - - return new ValueTask<T>(t); - } - /// <summary>Wake up all of the waiters and null out the field.</summary> /// <param name="waiters">The waiters.</param> /// <param name="result">The value with which to complete each waiter.</param> diff --git a/src/System.Threading.Channels/tests/ChannelTestBase.cs b/src/System.Threading.Channels/tests/ChannelTestBase.cs index e6b170ecec..04967a74e9 100644 --- a/src/System.Threading.Channels/tests/ChannelTestBase.cs +++ b/src/System.Threading.Channels/tests/ChannelTestBase.cs @@ -14,6 +14,7 @@ namespace System.Threading.Channels.Tests protected virtual bool RequiresSingleReader => false; protected virtual bool RequiresSingleWriter => false; + protected virtual bool BuffersItems => true; [Fact] public void ValidateDebuggerAttributes() @@ -288,6 +289,20 @@ namespace System.Threading.Channels.Tests } [Fact] + public void WaitToWriteAsync_EmptyChannel_SynchronouslyCompletes() + { + if (!BuffersItems) + { + return; + } + + Channel<int> c = CreateChannel(); + Task<bool> write = c.Writer.WaitToWriteAsync(); + Assert.Equal(TaskStatus.RanToCompletion, write.Status); + Assert.True(write.Result); + } + + [Fact] public void TryRead_DataAvailable_Success() { Channel<int> c = CreateChannel(); @@ -456,5 +471,33 @@ namespace System.Threading.Channels.Tests Task writeTask = c.Reader.WaitToReadAsync(new CancellationToken(true)); Assert.Equal(TaskStatus.Canceled, writeTask.Status); } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task WaitToReadAsync_DataWritten_CompletesSuccessfully(bool cancelable) + { + Channel<int> c = CreateChannel(); + CancellationToken token = cancelable ? new CancellationTokenSource().Token : default; + + Task<bool> read = c.Reader.WaitToReadAsync(token); + Assert.False(read.IsCompleted); + + Task write = c.Writer.WriteAsync(42, token); + + Assert.True(await read); + } + + [Fact] + public async Task WaitToReadAsync_NoDataWritten_Canceled_CompletesAsCanceled() + { + Channel<int> c = CreateChannel(); + var cts = new CancellationTokenSource(); + + Task<bool> read = c.Reader.WaitToReadAsync(cts.Token); + Assert.False(read.IsCompleted); + cts.Cancel(); + await Assert.ThrowsAnyAsync<OperationCanceledException>(() => read); + } } } diff --git a/src/System.Threading.Channels/tests/ChannelTests.cs b/src/System.Threading.Channels/tests/ChannelTests.cs index ffaf46ea9f..6ebfc77d69 100644 --- a/src/System.Threading.Channels/tests/ChannelTests.cs +++ b/src/System.Threading.Channels/tests/ChannelTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; using Xunit; @@ -43,20 +44,47 @@ namespace System.Threading.Channels.Tests Assert.False(co.AllowSynchronousContinuations); } + [Fact] + public void Create_ValidInputs_ProducesValidChannels() + { + Assert.NotNull(Channel.CreateBounded<int>(1)); + Assert.NotNull(Channel.CreateBounded<int>(new BoundedChannelOptions(1))); + + Assert.NotNull(Channel.CreateUnbuffered<int>()); + Assert.NotNull(Channel.CreateUnbuffered<int>(new UnbufferedChannelOptions())); + + Assert.NotNull(Channel.CreateUnbounded<int>()); + Assert.NotNull(Channel.CreateUnbounded<int>(new UnboundedChannelOptions())); + } + + [Fact] + public void Create_NullOptions_ThrowsArgumentException() + { + AssertExtensions.Throws<ArgumentNullException>("options", () => Channel.CreateUnbounded<int>(null)); + AssertExtensions.Throws<ArgumentNullException>("options", () => Channel.CreateUnbuffered<int>(null)); + AssertExtensions.Throws<ArgumentNullException>("options", () => Channel.CreateBounded<int>(null)); + } + [Theory] [InlineData(0)] [InlineData(-2)] public void CreateBounded_InvalidBufferSizes_ThrowArgumentExceptions(int capacity) { - Assert.Throws<ArgumentOutOfRangeException>("capacity", () => Channel.CreateBounded<int>(capacity)); - Assert.Throws<ArgumentOutOfRangeException>("capacity", () => new BoundedChannelOptions(capacity)); + AssertExtensions.Throws<ArgumentOutOfRangeException>("capacity", () => Channel.CreateBounded<int>(capacity)); + AssertExtensions.Throws<ArgumentOutOfRangeException>("capacity", () => new BoundedChannelOptions(capacity)); } [Theory] [InlineData((BoundedChannelFullMode)(-1))] [InlineData((BoundedChannelFullMode)(4))] public void BoundedChannelOptions_InvalidModes_ThrowArgumentExceptions(BoundedChannelFullMode mode) => - Assert.Throws<ArgumentOutOfRangeException>("value", () => new BoundedChannelOptions(1) { FullMode = mode }); + AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => new BoundedChannelOptions(1) { FullMode = mode }); + + [Theory] + [InlineData(0)] + [InlineData(-2)] + public void BoundedChannelOptions_InvalidCapacity_ThrowArgumentExceptions(int capacity) => + AssertExtensions.Throws<ArgumentOutOfRangeException>("value", () => new BoundedChannelOptions(1) { Capacity = capacity }); [Theory] [InlineData(1)] @@ -82,6 +110,22 @@ namespace System.Threading.Channels.Tests Assert.Equal(11, count); } + [Fact] + public void DefaultCompletion_NeverCompletes() + { + Task t = new TestChannelReader<int>(Enumerable.Empty<int>()).Completion; + Assert.False(t.IsCompleted); + } + + [Fact] + public async Task DefaultWriteAsync_CatchesTryWriteExceptions() + { + var w = new TryWriteThrowingWriter<int>(); + Task t = w.WriteAsync(42); + Assert.Equal(TaskStatus.Faulted, t.Status); + await Assert.ThrowsAsync<FormatException>(() => t); + } + private sealed class TestChannelWriter<T> : ChannelWriter<T> { private readonly Random _rand = new Random(42); @@ -137,6 +181,12 @@ namespace System.Threading.Channels.Tests Task.FromResult(true); } + private sealed class TryWriteThrowingWriter<T> : ChannelWriter<T> + { + public override bool TryWrite(T item) => throw new FormatException(); + public override Task<bool> WaitToWriteAsync(CancellationToken cancellationToken = default) => throw new InvalidDataException(); + } + private sealed class CanReadFalseStream : MemoryStream { public override bool CanRead => false; diff --git a/src/System.Threading.Channels/tests/UnbufferedChannelTests.cs b/src/System.Threading.Channels/tests/UnbufferedChannelTests.cs index e7e681de69..7ef42056ac 100644 --- a/src/System.Threading.Channels/tests/UnbufferedChannelTests.cs +++ b/src/System.Threading.Channels/tests/UnbufferedChannelTests.cs @@ -12,6 +12,7 @@ namespace System.Threading.Channels.Tests { protected override Channel<int> CreateChannel() => Channel.CreateUnbuffered<int>(); protected override Channel<int> CreateFullChannel() => CreateChannel(); + protected override bool BuffersItems => false; [Fact] public async Task Complete_BeforeEmpty_WaitingWriters_TriggersCompletion() |