public void InvokeActionMethodFilterAsynchronously_NormalExecutionNotCanceled()
        {
            // Arrange
            bool nextInChainWasCalled       = false;
            bool onActionExecutingWasCalled = false;
            bool onActionExecutedWasCalled  = false;

            ActionExecutingContext preContext   = GetActionExecutingContext();
            ActionFilterImpl       actionFilter = new ActionFilterImpl()
            {
                OnActionExecutingImpl = _ => { onActionExecutingWasCalled = true; },
                OnActionExecutedImpl  = _ => { onActionExecutedWasCalled = true; }
            };

            // Act
            Func <ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(actionFilter, preContext,
                                                                                                                            () => {
                nextInChainWasCalled = true;
                return(() => new ActionExecutedContext());
            });

            // Assert
            Assert.IsTrue(nextInChainWasCalled);
            Assert.IsTrue(onActionExecutingWasCalled, "OnActionExecuting() should've been called by the first invocation.");
            Assert.IsFalse(onActionExecutedWasCalled, "OnActionExecuted() shouldn't have been called by the first invocation.");

            continuation();
            Assert.IsTrue(onActionExecutedWasCalled, "OnActionExecuted() should've been called by the second invocation.");
        }
        public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutedException_ThreadAbort()
        {
            // Arrange
            ViewResult expectedResult = new ViewResult();

            bool onActionExecutedWasCalled = false;

            ActionExecutingContext preContext   = GetActionExecutingContext();
            ActionFilterImpl       actionFilter = new ActionFilterImpl()
            {
                OnActionExecutedImpl = filterContext => {
                    onActionExecutedWasCalled = true;
                    Thread.ResetAbort();
                }
            };

            // Act & assert
            Func <ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(actionFilter, preContext,
                                                                                                                            () => () => {
                Thread.CurrentThread.Abort();
                return(null);
            });

            ExceptionHelper.ExpectException <ThreadAbortException>(
                delegate {
                continuation();
            });

            // Assert
            Assert.IsTrue(onActionExecutedWasCalled, "OnActionExecuted() should've been called.");
        }
        public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutedException_Handled()
        {
            // Arrange
            ViewResult expectedResult = new ViewResult();

            bool nextInChainWasCalled      = false;
            bool onActionExecutedWasCalled = false;

            ActionExecutingContext preContext   = GetActionExecutingContext();
            ActionFilterImpl       actionFilter = new ActionFilterImpl()
            {
                OnActionExecutedImpl = filterContext => {
                    onActionExecutedWasCalled = true;
                    Assert.IsNotNull(filterContext.Exception);
                    filterContext.ExceptionHandled = true;
                    filterContext.Result           = expectedResult;
                }
            };

            // Act & assert pre-execution
            Func <ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(actionFilter, preContext,
                                                                                                                            () => () => {
                nextInChainWasCalled = true;
                throw new Exception("Some exception text.");
            });

            Assert.IsFalse(onActionExecutedWasCalled, "OnActionExecuted() shouldn't have been called yet.");

            // Act & assert post-execution
            ActionExecutedContext postContext = continuation();

            Assert.IsTrue(nextInChainWasCalled, "Next in chain should've been called.");
            Assert.IsTrue(onActionExecutedWasCalled, "OnActionExecuted() should've been called.");
            Assert.AreEqual(expectedResult, postContext.Result);
        }
        public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutingException_NotHandled()
        {
            // Arrange
            ViewResult expectedResult = new ViewResult();

            bool nextInChainWasCalled       = false;
            bool onActionExecutingWasCalled = false;
            bool onActionExecutedWasCalled  = false;

            ActionExecutingContext preContext   = GetActionExecutingContext();
            ActionFilterImpl       actionFilter = new ActionFilterImpl()
            {
                OnActionExecutingImpl = filterContext => { onActionExecutingWasCalled = true; },
                OnActionExecutedImpl  = filterContext => { onActionExecutedWasCalled = true; }
            };

            // Act & assert
            Assert.Throws <Exception>(
                delegate
            {
                AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(
                    actionFilter, preContext,
                    () =>
                {
                    nextInChainWasCalled = true;
                    throw new Exception("Some exception text.");
                });
            },
                @"Some exception text.");

            // Assert
            Assert.True(nextInChainWasCalled);
            Assert.True(onActionExecutingWasCalled);
            Assert.True(onActionExecutedWasCalled);
        }
        public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutingException_Handled()
        {
            // Arrange
            ViewResult expectedResult = new ViewResult();

            bool nextInChainWasCalled       = false;
            bool onActionExecutingWasCalled = false;
            bool onActionExecutedWasCalled  = false;

            ActionExecutingContext preContext   = GetActionExecutingContext();
            ActionFilterImpl       actionFilter = new ActionFilterImpl()
            {
                OnActionExecutingImpl = filterContext => { onActionExecutingWasCalled = true; },
                OnActionExecutedImpl  = filterContext =>
                {
                    onActionExecutedWasCalled = true;
                    Assert.NotNull(filterContext.Exception);
                    filterContext.ExceptionHandled = true;
                    filterContext.Result           = expectedResult;
                }
            };

            // Act
            Func <ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(
                actionFilter, preContext,
                () =>
            {
                nextInChainWasCalled = true;
                throw new Exception("Some exception text.");
            });

            // Assert
            Assert.True(nextInChainWasCalled);
            Assert.True(onActionExecutingWasCalled);
            Assert.True(onActionExecutedWasCalled);

            ActionExecutedContext postContext = continuation();

            Assert.Equal(expectedResult, postContext.Result);
        }
        public void InvokeActionMethodFilterAsynchronously_OnActionExecutingSetsResult()
        {
            // Arrange
            ViewResult expectedResult = new ViewResult();

            bool nextInChainWasCalled       = false;
            bool onActionExecutingWasCalled = false;
            bool onActionExecutedWasCalled  = false;

            ActionExecutingContext preContext   = GetActionExecutingContext();
            ActionFilterImpl       actionFilter = new ActionFilterImpl()
            {
                OnActionExecutingImpl = filterContext =>
                {
                    onActionExecutingWasCalled = true;
                    filterContext.Result       = expectedResult;
                },
                OnActionExecutedImpl = _ => { onActionExecutedWasCalled = true; }
            };

            // Act
            Func <ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(
                actionFilter, preContext,
                () =>
            {
                nextInChainWasCalled = true;
                return(() => new ActionExecutedContext());
            });

            // Assert
            Assert.False(nextInChainWasCalled);
            Assert.True(onActionExecutingWasCalled);
            Assert.False(onActionExecutedWasCalled);

            ActionExecutedContext postContext = continuation();

            Assert.False(onActionExecutedWasCalled);
            Assert.Equal(expectedResult, postContext.Result);
        }
        public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutingException_ThreadAbort()
        {
            // Arrange
            ViewResult expectedResult = new ViewResult();

            bool nextInChainWasCalled       = false;
            bool onActionExecutingWasCalled = false;
            bool onActionExecutedWasCalled  = false;

            ActionExecutingContext preContext   = GetActionExecutingContext();
            ActionFilterImpl       actionFilter = new ActionFilterImpl()
            {
                OnActionExecutingImpl = filterContext => { onActionExecutingWasCalled = true; },
                OnActionExecutedImpl  = filterContext =>
                {
                    onActionExecutedWasCalled = true;
                    Thread.ResetAbort();
                }
            };

            // Act & assert
            Assert.Throws <ThreadAbortException>(
                delegate
            {
                AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(
                    actionFilter, preContext,
                    () =>
                {
                    nextInChainWasCalled = true;
                    Thread.CurrentThread.Abort();
                    return(null);
                });
            });

            // Assert
            Assert.True(nextInChainWasCalled);
            Assert.True(onActionExecutingWasCalled);
            Assert.True(onActionExecutedWasCalled);
        }
        public void InvokeActionMethodFilterAsynchronously_NextInChainThrowsOnActionExecutingException_ThreadAbort()
        {
            // Arrange
            ViewResult expectedResult = new ViewResult();

            bool nextInChainWasCalled       = false;
            bool onActionExecutingWasCalled = false;
            bool onActionExecutedWasCalled  = false;

            ActionExecutingContext preContext   = GetActionExecutingContext();
            ActionFilterImpl       actionFilter = new ActionFilterImpl()
            {
                OnActionExecutingImpl = filterContext => {
                    onActionExecutingWasCalled = true;
                },
                OnActionExecutedImpl = filterContext => {
                    onActionExecutedWasCalled = true;
                    Thread.ResetAbort();
                }
            };

            // Act & assert
            ExceptionHelper.ExpectException <ThreadAbortException>(
                delegate {
                AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(actionFilter, preContext,
                                                                                    () => {
                    nextInChainWasCalled = true;
                    Thread.CurrentThread.Abort();
                    return(null);
                });
            });

            // Assert
            Assert.IsTrue(nextInChainWasCalled, "Next in chain should've been called.");
            Assert.IsTrue(onActionExecutingWasCalled, "OnActionExecuting() should've been called by the first invocation.");
            Assert.IsTrue(onActionExecutedWasCalled, "OnActionExecuted() should've been called due to exception handling.");
        }
        public void InvokeActionMethodFilterAsynchronously_OnActionExecutingSetsResult()
        {
            // Arrange
            ViewResult expectedResult = new ViewResult();

            bool nextInChainWasCalled       = false;
            bool onActionExecutingWasCalled = false;
            bool onActionExecutedWasCalled  = false;

            ActionExecutingContext preContext   = GetActionExecutingContext();
            ActionFilterImpl       actionFilter = new ActionFilterImpl()
            {
                OnActionExecutingImpl = filterContext => {
                    onActionExecutingWasCalled = true;
                    filterContext.Result       = expectedResult;
                },
                OnActionExecutedImpl = _ => { onActionExecutedWasCalled = true; }
            };

            // Act
            Func <ActionExecutedContext> continuation = AsyncControllerActionInvoker.InvokeActionMethodFilterAsynchronously(actionFilter, preContext,
                                                                                                                            () => {
                nextInChainWasCalled = true;
                return(() => new ActionExecutedContext());
            });

            // Assert
            Assert.IsFalse(nextInChainWasCalled, "Next in chain shouldn't have been called due to short circuiting.");
            Assert.IsTrue(onActionExecutingWasCalled, "OnActionExecuting() should've been called by the first invocation.");
            Assert.IsFalse(onActionExecutedWasCalled, "OnActionExecuted() shouldn't have been called by the first invocation.");

            ActionExecutedContext postContext = continuation();

            Assert.IsFalse(onActionExecutedWasCalled, "OnActionExecuted() shouldn't have been called by the second invocation.");
            Assert.AreEqual(expectedResult, postContext.Result);
        }