public void MultipleAspect_ThrowException_In_OnEntry_Handled_InnerAspects_OnEntry_OnExit_Called()
        {
            // Arrange
            var afterBreaker = new ObservableAspect {
                InternalOrder = 2
            };
            var breaker = new ThrowAspect(typeof(ApplicationException), BoundaryType.Entry)
            {
                InternalOrder = 1
            };
            var beforeBreaker = new ObservableAspect()
            {
                InternalOrder = 0
            };

            var pipeline = CreatePipeline <IService>(
                new Service(), nameof(IService.Identity),
                Args.Pack <MethodBoundaryAspect>(beforeBreaker, breaker, afterBreaker),
                Args.Box(10));

            // Assert
            Assert.Throws <ApplicationException>(() => _executor.ExecutePipeline(pipeline, pipeline.Invocation));
            Assert.Empty(afterBreaker.ExecutionStack);
            Assert.Equal(new []
            {
                new BoundaryState(BoundaryType.Exit),
                new BoundaryState(BoundaryType.Entry),
            }, beforeBreaker.ExecutionStack);

            Assert.Equal(new []
            {
                new BoundaryState(BoundaryType.Entry)
            }, breaker.ExecutionStack);
        }
        public void SingleAspect_If_UnhandledException_Occuring_InBoundary_It_Breakes_Pipeline_And_Throws_Outsite()
        {
            // Arrange
            var aspect   = new ThrowAspect(typeof(ArgumentException), BoundaryType.Entry, throwAsUnhandled: true);
            var pipeline = CreatePipeline <IService>(
                new Service(), nameof(IService.Identity), Args.Pack(aspect), Args.Box(10));

            // Act && Assert
            Assert.Throws <ArgumentException>(() => _executor.ExecutePipeline(pipeline, pipeline.Invocation));

            InvocationAssert.ProceedNotCalled(pipeline.Invocation);
            Assert.Equal(BoundaryType.Entry, aspect.ExecutionStack.Pop().BoundaryType);
        }
        public void SingleAspect_NormalFlow_AspectBoundariesCalled()
        {
            // Arrange
            var aspect   = new ObservableAspect();
            var pipeline = CreatePipeline <IService>(
                new Service(), nameof(IService.Identity), Args.Pack(aspect), Args.Box(10));

            // Act
            _executor.ExecutePipeline(pipeline, pipeline.Invocation);

            // Assert
            InvocationAssert.ProceedCalled(pipeline.Invocation);
            Assert.Equal(_normalExecutionStack, aspect.ExecutionStack);
        }
        public void SingleAspect_If_HandledException_Occuring_InBoundary_OnEntry_OtherAspectsShouldNotBeCalled()
        {
            // Arrange
            var aspect   = new ThrowAspect(typeof(ArgumentException), BoundaryType.Entry);
            var pipeline = CreatePipeline <IService>(
                new Service(), nameof(IService.Identity), Args.Pack(aspect), Args.Box(10));

            // Act && Assert
            Assert.Throws <ArgumentException>(() => _executor.ExecutePipeline(pipeline, pipeline.Invocation));

            InvocationAssert.ProceedNotCalled(pipeline.Invocation);
            Assert.Equal(new[]
            {
                new BoundaryState(BoundaryType.Entry),
            }, aspect.ExecutionStack);
        }
        public void SingleAspect_If_ReturnCalled_InPipeline_Method_ShouldNot_BeCalled()
        {
            // Arrange
            var aspect   = new ReturnDefaultValueAspect(BoundaryType.Entry);
            var pipeline = CreatePipeline <IService>(
                new Service(), nameof(IService.Identity), Args.Pack(aspect), Args.Box(10));

            // Act
            _executor.ExecutePipeline(pipeline, pipeline.Invocation);

            // Assert

            InvocationAssert.ProceedNotCalled(pipeline.Invocation);

            Assert.Equal(new[]
            {
                new BoundaryState(BoundaryType.Entry)
            }, aspect.ExecutionStack);
        }
        public async Task SingleAspect_UnhandledException_ShouldBreakPipeline()
        {
            // Arrange
            var aspect   = new ThrowAspect(typeof(ArgumentException), BoundaryType.Entry, throwAsUnhandled: true);
            var pipeline = CreatePipeline <IService>(
                new Service(), nameof(IService.IdentityAsync), Args.Pack(aspect), Args.Box(10));

            // Act
            _executor.ExecutePipeline(pipeline, pipeline.Invocation);

            await Assert.ThrowsAsync <ArgumentException>(
                async() => await Await <int>(pipeline.Invocation));

            // Assert
            Assert.Equal(new [] { new BoundaryState(BoundaryType.Entry) }, aspect.ExecutionStack);

            Assert.IsType <ArgumentException>(pipeline.CurrentException);
            InvocationAssert.ProceedNotCalled(pipeline.Invocation);
        }
        public void SingleAspect_CallThrow_AfterMethodExecution_ShouldThrow()
        {
            // Arrange
            var aspect   = new ThrowAspect(typeof(ArgumentException), BoundaryType.Success, throwAsUnhandled: false);
            var pipeline = CreatePipeline <IService>(
                new Service(), nameof(IService.Identity), Args.Pack(aspect), Args.Box(10));

            // Act
            Assert.Throws <ArgumentException>(() => _executor.ExecutePipeline(pipeline, pipeline.Invocation));

            // Assert
            Assert.Equal(new []
            {
                new BoundaryState(BoundaryType.Success),
                new BoundaryState(BoundaryType.Entry)
            }, aspect.ExecutionStack);

            Assert.IsType <ArgumentException>(pipeline.CurrentException);
            InvocationAssert.ProceedCalled(pipeline.Invocation);
        }
        public void MultipleAspects_OnEntry_ReturnResult_OnSuccess_NotCalled_OnTriggered_Aspect_But_On_OuterAspects()
        {
            // Arrange
            var afterBreaker1 = new ObservableAspect {
                InternalOrder = 3
            };
            var afterBreaker2 = new ObservableAspect {
                InternalOrder = 2
            };
            var breaker = new ReturnDefaultValueAspect(BoundaryType.Entry)
            {
                InternalOrder = 1
            };
            var beforeBreaker = new ObservableAspect {
                InternalOrder = 0
            };

            var pipeline = CreatePipeline <IService>(
                new Service(), nameof(IService.Identity),
                Args.Pack(beforeBreaker, breaker, afterBreaker1, afterBreaker2),
                Args.Box(10));

            // Act
            _executor.ExecutePipeline(pipeline, pipeline.Invocation);

            // Assert

            // Метод не вызвался, т.к. 2й аспект вернул результат
            InvocationAssert.ProceedNotCalled(pipeline.Invocation);
            // Первый аспект прошел весь нормальный флоу
            Assert.Equal(_normalExecutionStack, beforeBreaker.ExecutionStack);
            // Второй вернул результат и кроме OnEntry ничего не выполнилось
            Assert.Equal(new[]
            {
                new BoundaryState(BoundaryType.Entry)
            }, breaker.ExecutionStack);

            // Остальные не выполнились
            Assert.Empty(afterBreaker1.ExecutionStack);
            Assert.Empty(afterBreaker2.ExecutionStack);
        }
        public void SingleAspect_CallReturn_AfterMethodExecution_ShouldChangeResult()
        {
            // Arrange
            var aspect   = new IncrementReturnValueOnSuccess();
            var pipeline = CreatePipeline <IService>(
                new Service(), nameof(IService.Identity), Args.Pack(aspect), Args.Box(10));

            // Act
            _executor.ExecutePipeline(pipeline, pipeline.Invocation);

            // Assert
            Assert.Equal(11, pipeline.Invocation.ReturnValue);
            Assert.Equal(new []
            {
                new BoundaryState(BoundaryType.Success),
                new BoundaryState(BoundaryType.Entry),
            }, aspect.ExecutionStack);
            Assert.Equal(11, pipeline.CurrentReturnValue);

            InvocationAssert.ProceedCalled(pipeline.Invocation);
        }
        public async Task SingleAspect_NormalFlow_AspectBoundariesCalled()
        {
            // Arrange
            var aspect   = new ObservableAspect();
            var pipeline = CreatePipeline <IService>(
                new Service(), nameof(IService.IdentityAsync), Args.Pack(aspect), Args.Box(10));

            // Act
            _executor.ExecutePipeline(pipeline, pipeline.Invocation);

            // Assert
            Assert.Equal(new [] { new BoundaryState(BoundaryType.Entry) }, aspect.ExecutionStack);

            var result = await Await <int>(pipeline.Invocation);

            Assert.Equal(10, result);
            Assert.Equal(_normalExecutionStack, aspect.ExecutionStack);
            Assert.Equal(10, pipeline.CurrentReturnValue);

            InvocationAssert.ProceedCalled(pipeline.Invocation);
        }
        public async Task SingleAspect_ReturnOnEntry_ShouldNotCallBoundaries()
        {
            // Arrange
            var aspect   = new ReturnValueAspect(BoundaryType.Entry, valueToReturn: 25);
            var pipeline = CreatePipeline <IService>(
                new Service(), nameof(IService.IdentityAsync), Args.Pack(aspect), Args.Box(10));

            // Act
            _executor.ExecutePipeline(pipeline, pipeline.Invocation);
            var result = await Await <int>(pipeline.Invocation);

            // Assert
            Assert.Equal(25, result);
            Assert.Equal(new []
            {
                new BoundaryState(BoundaryType.Entry),
            }, aspect.ExecutionStack);

            Assert.Equal(25, pipeline.CurrentReturnValue);

            InvocationAssert.ProceedNotCalled(pipeline.Invocation);
        }