[PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static async Task BeginContext_handler_flows_into_new_thread()
        {
            var source  = new TaskCompletionSource <object?>();
            var watcher = new CallbackWatcher();

            var thread = new Thread(() =>
            {
                try
                {
                    using (watcher.ExpectCallback())
                        AmbientTasks.Add(Task.FromException(new Exception()));

                    source.SetResult(null);
                }
                catch (Exception ex)
                {
                    source.SetException(ex);
                }
            });

            AmbientTasks.BeginContext(ex => watcher.OnCallback());

            thread.Start();

            await source.Task;
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void Handler_should_be_called_one_additional_time_to_handle_its_own_exception()
        {
            var taskException    = new Exception();
            var handlerException = new Exception();
            var watcher          = new CallbackWatcher();

            AmbientTasks.BeginContext(ex =>
            {
                watcher.OnCallback(out var callCount);

                if (callCount == 1)
                {
                    throw handlerException;
                }

                ex.ShouldBe(handlerException);
            });

            using (watcher.ExpectCallback(count: 2))
                AmbientTasks.Add(Task.FromException(taskException));

            var waitAllTask = AmbientTasks.WaitAllAsync();

            waitAllTask.Status.ShouldBe(TaskStatus.Faulted);

            var aggregateException = waitAllTask.Exception !.InnerExceptions.ShouldHaveSingleItem().ShouldBeOfType <AggregateException>();

            aggregateException.InnerExceptions.ShouldHaveSingleItem().ShouldBeSameAs(taskException);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void WaitAllAsync_does_not_reset_until_all_tasks_have_completed()
        {
            var source1 = new TaskCompletionSource <object?>();
            var source2 = new TaskCompletionSource <object?>();

            AmbientTasks.Add(source1.Task);
            var waitTaskSeenAfterFirstAdd = AmbientTasks.WaitAllAsync();

            waitTaskSeenAfterFirstAdd.IsCompleted.ShouldBeFalse();

            // Should not reset on next call
            AmbientTasks.WaitAllAsync().ShouldBeSameAs(waitTaskSeenAfterFirstAdd);

            AmbientTasks.Add(source2.Task);
            AmbientTasks.WaitAllAsync().ShouldBeSameAs(waitTaskSeenAfterFirstAdd);

            // Should not reset on next call
            AmbientTasks.WaitAllAsync().ShouldBeSameAs(waitTaskSeenAfterFirstAdd);

            source1.SetResult(null);
            AmbientTasks.WaitAllAsync().ShouldBeSameAs(waitTaskSeenAfterFirstAdd);

            // Should not reset on next call
            AmbientTasks.WaitAllAsync().ShouldBeSameAs(waitTaskSeenAfterFirstAdd);

            source2.SetResult(null);
            waitTaskSeenAfterFirstAdd.Status.ShouldBe(TaskStatus.RanToCompletion);
            AmbientTasks.WaitAllAsync().Status.ShouldBe(TaskStatus.RanToCompletion);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static async Task BeginContext_handler_flows_into_ThreadPool_QueueUserWorkItem()
        {
            var watcher = new CallbackWatcher();

            AmbientTasks.BeginContext(ex => watcher.OnCallback());

            var source = new TaskCompletionSource <object?>();

            ThreadPool.QueueUserWorkItem(_ =>
            {
                try
                {
                    using (watcher.ExpectCallback())
                        AmbientTasks.Add(Task.FromException(new Exception()));

                    source.SetResult(null);
                }
                catch (Exception ex)
                {
                    source.SetException(ex);
                }
            }, null);

            await source.Task;
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void WaitAllAsync_should_fault_after_adding_synchronously_failed_task_with_no_context()
        {
            Should.Throw <AggregateException>(
                () => AmbientTasks.Add(Task.FromException(new Exception())));

            AmbientTasks.WaitAllAsync().Status.ShouldBe(TaskStatus.Faulted);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void Passed_synchronization_context_is_used_for_post([Values] PostOverload overload)
        {
            using (SynchronizationContextAssert.ExpectSinglePost(postedAction => { }))
            {
                var contextToUse = SynchronizationContext.Current !;

                using (SynchronizationContextAssert.ExpectNoPost())
                {
                    switch (overload)
                    {
                    case PostOverload.Action:
                        AmbientTasks.Post(contextToUse, () => { });
                        break;

                    case PostOverload.SendOrPostCallback:
                        AmbientTasks.Post(contextToUse, state => { }, state: null);
                        break;

                    case PostOverload.AsyncAction:
                        AmbientTasks.Post(contextToUse, () => Task.CompletedTask);
                        break;

                    default:
                        throw new NotImplementedException();
                    }
                }
            }
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void WaitAllAsync_does_not_complete_until_async_task_added_by_user_delegate_completes([Values] PostOverload overload)
        {
            var source       = new TaskCompletionSource <object?>();
            var postedAction = (Action?)null;

            using (SynchronizationContextAssert.ExpectSinglePost(p => postedAction = p))
            {
                AmbientTasksPost(overload, () =>
                {
                    AmbientTasks.Add(source.Task);
                });
            }

            var waitAllTask = AmbientTasks.WaitAllAsync();

            waitAllTask.IsCompleted.ShouldBeFalse();

            postedAction.ShouldNotBeNull();
            postedAction !.Invoke();

            waitAllTask.IsCompleted.ShouldBeFalse();

            source.SetResult(null);

            waitAllTask.Status.ShouldBe(TaskStatus.RanToCompletion);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void WaitAllAsync_should_reset_after_fault_is_displayed_in_previously_returned_task()
        {
            Should.Throw <AggregateException>(
                () => AmbientTasks.Add(Task.FromException(new Exception())));

            AmbientTasks.WaitAllAsync().Status.ShouldBe(TaskStatus.Faulted);
            AmbientTasks.WaitAllAsync().Status.ShouldBe(TaskStatus.RanToCompletion);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void Handled_exceptions_do_not_appear_in_a_subsequent_call_to_WaitAllAsync()
        {
            AmbientTasks.BeginContext(handler => { });

            AmbientTasks.Add(Task.FromException(new Exception()));

            AmbientTasks.WaitAllAsync().Status.ShouldBe(TaskStatus.RanToCompletion);
        }
Beispiel #10
0
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void Func_returning_synchronously_canceled_task_is_noop()
        {
            var source = new TaskCompletionSource <object?>();

            source.SetCanceled();
            AmbientTasks.Add(() => source.Task);

            AmbientTasks.WaitAllAsync().Status.ShouldBe(TaskStatus.RanToCompletion);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void Adding_synchronously_faulted_task_with_no_context_throws_AggregateException_synchronously()
        {
            var exception = new Exception();

            var aggregateException = Should.Throw <AggregateException>(
                () => AmbientTasks.Add(Task.FromException(exception)));

            aggregateException.InnerExceptions.ShouldBe(new[] { exception });
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void WaitAllAsync_should_fault_after_adding_synchronously_failed_task_with_no_context_when_on_SynchronizationContext()
        {
            using (SynchronizationContextAssert.ExpectSinglePost(postedAction => { }))
            {
                AmbientTasks.Add(Task.FromException(new Exception()));

                AmbientTasks.WaitAllAsync().Status.ShouldBe(TaskStatus.Faulted);
            }
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void Exception_from_user_delegate_is_not_thrown_on_SynchronizationContext_when_there_is_a_BeginContext_handler([Values] PostOverload overload)
        {
            AmbientTasks.BeginContext(ex => { });

            using (SynchronizationContextAssert.ExpectSinglePost(postedAction => postedAction.Invoke()))
            {
                AmbientTasksPost(overload, () => throw new Exception());
            }
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static async Task BeginContext_handler_does_not_flow_from_inner_method_back_to_outer_method_after_await()
        {
            var watcher = new CallbackWatcher();

            AmbientTasks.BeginContext(ex => watcher.OnCallback());

            await InnerFunction();

            using (watcher.ExpectCallback())
                AmbientTasks.Add(Task.FromException(new Exception()));
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void Exception_from_user_delegate_is_not_in_task_from_next_call_to_WaitAllAsync_when_there_is_a_BeginContext_handler([Values] PostOverload overload)
        {
            AmbientTasks.BeginContext(ex => { });

            using (SynchronizationContextAssert.ExpectSinglePost(postedAction => postedAction.Invoke()))
            {
                AmbientTasksPost(overload, () => throw new Exception());
            }

            AmbientTasks.WaitAllAsync().Status.ShouldBe(TaskStatus.RanToCompletion);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void Exception_from_SynchronizationContext_post_before_invoking_delegate_is_not_handled_when_there_is_a_BeginContext_handler([Values] PostOverload overload)
        {
            AmbientTasks.BeginContext(ex => { });

            var exception = new Exception();

            using (SynchronizationContextAssert.ExpectSinglePost(postedAction => throw exception))
            {
                Should.Throw <Exception>(() => AmbientTasksPost(overload, () => { })).ShouldBeSameAs(exception);
            }
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void BeginContext_handler_is_replaced_with_next_call()
        {
            AmbientTasks.BeginContext(ex => Assert.Fail("This handler should not be called."));

            var watcher = new CallbackWatcher();

            AmbientTasks.BeginContext(ex => watcher.OnCallback());

            using (watcher.ExpectCallback())
                AmbientTasks.Add(Task.FromException(new Exception()));
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static async Task BeginContext_handler_flows_across_await()
        {
            var watcher = new CallbackWatcher();

            AmbientTasks.BeginContext(ex => watcher.OnCallback());

            await Task.Yield();

            using (watcher.ExpectCallback())
                AmbientTasks.Add(Task.FromException(new Exception()));
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static async Task BeginContext_handler_flows_into_Task_Run()
        {
            var watcher = new CallbackWatcher();

            AmbientTasks.BeginContext(ex => watcher.OnCallback());

            await Task.Run(() =>
            {
                using (watcher.ExpectCallback())
                    AmbientTasks.Add(Task.FromException(new Exception()));
            });
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void SynchronizationContext_that_throws_on_post_does_not_prevent_WaitAllAsync_completion()
        {
            var source = new TaskCompletionSource <object?>();

            using (SynchronizationContextAssert.ExpectSinglePost(postedAction => throw new Exception()))
            {
                AmbientTasks.Add(source.Task);

                var waitAllTask = AmbientTasks.WaitAllAsync();
                source.SetException(new Exception());
                waitAllTask.Status.ShouldBe(TaskStatus.Faulted);
            }
        }
Beispiel #21
0
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void BeginContext_handler_receives_exception_thrown_from_func()
        {
            var exception = new Exception();
            var watcher   = new CallbackWatcher();

            AmbientTasks.BeginContext(ex =>
            {
                watcher.OnCallback();
                ex.ShouldBeSameAs(exception);
            });

            using (watcher.ExpectCallback())
                AmbientTasks.Add(() => throw exception);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void WaitAllAsync_waits_for_added_task_with_no_context_to_fault()
        {
            var source = new TaskCompletionSource <object?>();

            AmbientTasks.Add(source.Task);

            var waitAllTask = AmbientTasks.WaitAllAsync();

            waitAllTask.IsCompleted.ShouldBeFalse();

            source.SetException(new Exception());
            waitAllTask.Status.ShouldBe(TaskStatus.Faulted);
            AmbientTasks.WaitAllAsync().Status.ShouldBe(TaskStatus.RanToCompletion);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void Adding_synchronously_faulted_task_with_no_context_throws_AggregateException_on_current_SynchronizationContext()
        {
            var exception = new Exception();

            using (SynchronizationContextAssert.ExpectSinglePost(postedAction =>
            {
                var aggregateException = Should.Throw <AggregateException>(postedAction);

                aggregateException.InnerExceptions.ShouldBe(new[] { exception });
            }))
            {
                AmbientTasks.Add(Task.FromException(exception));
            }
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void BeginContext_handler_receives_exceptions_from_synchronously_faulted_tasks()
        {
            var exception = new Exception();
            var watcher   = new CallbackWatcher();

            AmbientTasks.BeginContext(ex =>
            {
                watcher.OnCallback();
                ex.ShouldBeSameAs(exception);
            });

            using (watcher.ExpectCallback())
                AmbientTasks.Add(Task.FromException(exception));
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void BeginContext_handler_can_be_removed()
        {
            AmbientTasks.BeginContext(ex => Assert.Fail("This handler should not be called."));

            AmbientTasks.BeginContext();

            var exception          = new Exception();
            var aggregateException = Should.Throw <AggregateException>(
                () => AmbientTasks.Add(Task.FromException(exception)));

            aggregateException.InnerExceptions.ShouldHaveSingleItem().ShouldBeSameAs(exception);

            AmbientTasks.WaitAllAsync().Status.ShouldBe(TaskStatus.Faulted);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void BeginContext_handler_is_not_executed_using_synchronization_context()
        {
            using (SynchronizationContextAssert.ExpectNoPost())
            {
                AmbientTasks.BeginContext(ex => { });

                AmbientTasks.Add(Task.FromException(new Exception()));

                using (Utils.WithTemporarySynchronizationContext(null))
                {
                    AmbientTasks.Add(Task.FromException(new Exception()));
                }
            }
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void WaitAllAsync_resets_after_overlapping_tasks_fail()
        {
            var source1 = new TaskCompletionSource <object?>();
            var source2 = new TaskCompletionSource <object?>();

            AmbientTasks.Add(source1.Task);
            AmbientTasks.Add(source2.Task);

            var waitAllTaskBeforeAllExceptions = AmbientTasks.WaitAllAsync();

            source1.SetException(new Exception());
            source2.SetException(new Exception());

            waitAllTaskBeforeAllExceptions.Status.ShouldBe(TaskStatus.Faulted);
            AmbientTasks.WaitAllAsync().Status.ShouldBe(TaskStatus.RanToCompletion);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static async Task WaitAllAsync_should_throw_AggregateException_when_awaited()
        {
            var source = new TaskCompletionSource <object?>();

            AmbientTasks.Add(source.Task);

            var waitAllTask = AmbientTasks.WaitAllAsync();

            var exception = new Exception();

            source.SetException(exception);

            var aggregateException = await Should.ThrowAsync <AggregateException>(waitAllTask);

            aggregateException.InnerExceptions.ShouldBe(new[] { exception });
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void Adding_synchronously_faulted_task_with_multiple_exceptions_and_no_context_throws_AggregateException_synchronously_with_all_exceptions()
        {
            var exceptions = new[]
            {
                new Exception(),
                new Exception()
            };

            var source = new TaskCompletionSource <object?>();

            source.SetException(exceptions);

            var aggregateException = Should.Throw <AggregateException>(() => AmbientTasks.Add(source.Task));

            aggregateException.InnerExceptions.ShouldBe(exceptions);
        }
        [PreventExecutionContextLeaks] // Workaround for https://github.com/nunit/nunit/issues/3283
        public static void Handled_exceptions_do_not_appear_in_task_returned_from_WaitAllAsync_while_waiting_for_task()
        {
            var source    = new TaskCompletionSource <object?>();
            var exception = new Exception();

            AmbientTasks.BeginContext(handler => { });

            AmbientTasks.Add(source.Task);

            var waitAllTask = AmbientTasks.WaitAllAsync();

            waitAllTask.IsCompleted.ShouldBeFalse();

            source.SetException(exception);

            waitAllTask.Status.ShouldBe(TaskStatus.RanToCompletion);
        }