public void CompleteAbortsPendingWriteTasks()
        {
            var sut        = new BufferedChannel <int>(0);
            var writeTask1 = sut.WriteAsync(1);
            var writeTask2 = sut.WriteAsync(2);

            sut.Complete();
            Should.Throw <TaskCanceledException>(() => writeTask1, Timeout1Sec);
            Should.Throw <TaskCanceledException>(() => writeTask2, Timeout1Sec);
        }
        public void WriteAsyncCompletesWhenThereIsBufferSpaceAvailable()
        {
            var sut = new BufferedChannel <int>(1);

            Should.CompleteIn(sut.WriteAsync(1), Timeout1Sec);
            var writeTask = sut.WriteAsync(2);

            writeTask.IsCompleted.ShouldBe(false);
            sut.TryRead(out var item).ShouldBe(true);
            item.ShouldBe(1);
            Should.CompleteIn(writeTask, Timeout1Sec);
            sut.TryRead(out item).ShouldBe(true);
            item.ShouldBe(2);
        }
#pragma warning disable xUnit1026 // Theory methods should use all of their parameters
        public void CanWriteAndReadFromSeveralThreadsConcurrently(int writeThreads, int readThreads, int bufferSize)
#pragma warning restore xUnit1026 // Theory methods should use all of their parameters
        {
            var writeCount = readThreads * 100;
            var readCount  = writeThreads * 100;
            var sut        = new BufferedChannel <int>(bufferSize);

            async Task WriteWorker()
            {
                for (var i = 0; i < writeCount; i++)
                {
                    await sut.WriteAsync(i).ConfigureAwait(false);
                }
            }

            async Task ReadWorker()
            {
                for (var i = 0; i < readCount; i++)
                {
                    await sut.ReadAsync().ConfigureAwait(false);
                }
            }

            var writeTasks = Enumerable.Range(0, writeThreads).Select(_ => Task.Run(WriteWorker));
            var readTasks  = Enumerable.Range(0, readThreads).Select(_ => Task.Run(ReadWorker));
            var allTasks   = writeTasks.Concat(readTasks).ToArray();

            Task.WhenAll(allTasks).ShouldCompleteIn(Timeout10Sec);

            sut.TryRead(out int _).ShouldBe(false);
            sut.TryComplete().ShouldBe(true);
        }
        public void CannotWriteAfterCompletion()
        {
            var sut = new BufferedChannel <int>(2);

            sut.TryWrite(1);
            sut.Complete();
            sut.TryWrite(2).ShouldBe(false);
            Should.Throw <OperationCanceledException>(() => sut.WriteAsync(2));
        }
        public void ReadsSynchronouslyWhenThereIsPendingWriteTask()
        {
            var sut       = new BufferedChannel <int>(0);
            var writeTask = sut.WriteAsync(3);

            sut.TryReadSafe(out int item).ShouldBe(true);
            item.ShouldBe(3);
            Should.CompleteIn(writeTask, TimeSpan.FromSeconds(1));
        }
        public void WritesSynchronouslyWhenThereIsPendingReadTask()
        {
            var sut      = new BufferedChannel <int>(0);
            var readTask = sut.ReadAsync();

            sut.TryWriteSafe(1).ShouldBe(false);
            sut.WriteAsync(1).ShouldCompleteIn(Timeout1Sec);
            Should.CompleteIn(readTask.AsTask(), TimeSpan.FromSeconds(1));
            readTask.Result.ShouldBe(1);
        }
        public void TerminatesOnWriteTimeout()
        {
            var sut = new BufferedChannel <int>(1, Timeout100Ms);

            Should.NotThrow(sut.WriteAsync(1), Timeout1Sec);
            sut.TryWrite(1).ShouldBe(false);
            Should.Throw <ChannelWriteTimeoutException>(sut.WaitWriteAvailableAsync(), Timeout1Sec);
            Should.Throw <ChannelWriteTimeoutException>(sut.Out.Completion, Timeout1Sec);
            sut.TryRead(out _).ShouldBe(true);
            Should.Throw <Exception>(sut.Completion, Timeout1Sec);
        }
        public async Task SlidesWriteTimeoutAfterWriteAvailable()
        {
            var sut = new BufferedChannel <int>(1, Timeout50Ms);

            sut.TryWrite(1).ShouldBe(true);
            await Task.Delay(Timeout10Ms).ConfigureAwait(false);

            sut.TryRead(out _).ShouldBe(true);
            await Task.Delay(Timeout100Ms).ConfigureAwait(false);

            sut.Out.Completion.IsCompleted.ShouldBeFalse();
            Should.NotThrow(() => sut.WriteAsync(1), Timeout1Sec);
            await Task.Delay(Timeout10Ms).ConfigureAwait(false);

            sut.TryRead(out _).ShouldBe(true);
        }