Example #1
0
        public async Task IfElseState_WithExistingTransitionToStates_BuildRuntimeStateAndExecute()
        {
            var tracker = new TestTracker();

            var predicateValue = false;

            var state = new IfElseState("test")
            {
                OnEnterAction    = tracker.StateEnterAction,
                OnExitAction     = tracker.StateExitAction,
                OnCanceledAction = tracker.StateCanceledAction,
                Predicate        = () => predicateValue,
                ElseTransition   = new Transition("else")
                {
                    Action = tracker.TransitionAction,
                    Target = new StateTarget("state1"),
                },
                TrueTransition = new Transition("true")
                {
                    Action = tracker.TransitionAction,
                    Target = new StateTarget("state2"),
                },
            };

            var states = new RuntimeStateBase[]
            {
                new SimpleState("state1")
                {
                    OnEnterAction    = tracker.StateEnterAction,
                    OnExecuteAction  = tracker.StateExecutionAction,
                    OnExitAction     = tracker.StateExitAction,
                    OnCanceledAction = tracker.StateCanceledAction,
                }.BuildRuntimeState(),
                new SimpleState("state2")
                {
                    OnEnterAction    = tracker.StateEnterAction,
                    OnExecuteAction  = tracker.StateExecutionAction,
                    OnExitAction     = tracker.StateExitAction,
                    OnCanceledAction = tracker.StateCanceledAction,
                }.BuildRuntimeState(),
            };

            var runtimeState = state.BuildRuntimeState(states);

            var runtimeTransition = await runtimeState.ExecuteAsync(CancellationToken.None);

            Assert.Equal(state.ElseTransition.Target.Name, runtimeTransition.Target.Name);
            Assert.Equal(">test;<test;", tracker.ToString());

            predicateValue = true;

            tracker.Clear();

            runtimeTransition = await runtimeState.ExecuteAsync(CancellationToken.None);

            Assert.Equal(state.TrueTransition.Target.Name, runtimeTransition.Target.Name);
            Assert.Equal(">test;<test;", tracker.ToString());
        }
Example #2
0
        public async Task ExecuteAsync_WithCancellationWithoutTransitions_CompletesImmediatellyAndRunsCanceledActionAndThrowsOperationCanceledException()
        {
            using (var cts = new CancellationTokenSource())
            {
                var tcs = new TaskCompletionSource <object>();

                var tracker = new TestTracker();

                var state = new SimpleRuntimeState(
                    "test",
                    tracker.StateEnterAction,
                    async s =>
                {
                    await tracker.StateExecutionAction(s);
                    await tcs.Task;
                },
                    tracker.StateExitAction,
                    tracker.StateCanceledAction);

                var task = state.ExecuteAsync(cts.Token);

                cts.Cancel();
                tcs.SetResult(null);

                await Assert.ThrowsAsync <OperationCanceledException>(async() => await task);

                Assert.Equal(">test;*test;!test;", tracker.ToString());
            }
        }
Example #3
0
        public async Task ExecuteAsync_WithoutSelectedTransitionAndNotCanceled_ReturnElseTransitionAndRunsEnterAndExitActions()
        {
            var tracker = new TestTracker();

            var elseTransition = new RuntimeTransition("Else", A.Fake <ITransitionTarget>(), tracker.TransitionAction, null);

            var state = A.Fake <ChoiceRuntimeStateBase>(builder =>
                                                        builder
                                                        .WithArgumentsForConstructor(new object[]
            {
                "test",
                tracker.StateEnterAction,
                tracker.StateExitAction,
                tracker.StateCanceledAction,
                elseTransition,
            })
                                                        .CallsBaseMethods());

            A.CallTo(state)
            .Where(call => call.Method.Name == "SelectTransition")
            .WithReturnType <RuntimeTransition>()
            .Returns(null);

            var actual = await state.ExecuteAsync(CancellationToken.None);

            Assert.Equal(elseTransition, actual);

            Assert.Equal(">test;<test;", tracker.ToString());
        }
Example #4
0
        public async Task ExecuteAsync_WithoutCancellationAndNonTargettedTransitions_RunsEnterAndExecutesTransitionsUntilTargettedTransitionAndExitActionsAndReturnsTargettedTransitionWithoutExecuting()
        {
            var tracker = new TestTracker();

            var targetedTransition    = new RuntimeTransition("Targeted", A.Fake <ITransitionTarget>(), tracker.TransitionAction, null);
            var nonTargetedTransition = new RuntimeTransition("NonTargeted", null, tracker.TransitionAction, null);

            var state = A.Fake <RuntimeStateBase>(builder =>
                                                  builder
                                                  .WithArgumentsForConstructor(new object[]
            {
                "test",
                tracker.StateEnterAction,
                tracker.StateExitAction,
                tracker.StateCanceledAction,
            })
                                                  .CallsBaseMethods());

            A.CallTo(state)
            .Where(call => call.Method.Name == "ExecuteStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .ReturnsNextFromSequence(nonTargetedTransition, nonTargetedTransition, targetedTransition);

            var actual = await state.ExecuteAsync(CancellationToken.None);

            Assert.Equal(targetedTransition, actual);
            Assert.Equal(">test;@test;@test;<test;", tracker.ToString());
        }
Example #5
0
        public async Task ExecuteAsync_WithCancellationDuringExecute_RunsEnterAndExitActionsAndThrowsOperationCanceledException()
        {
            var tracker = new TestTracker();

            using (var cts = new CancellationTokenSource())
            {
                var state = A.Fake <RuntimeStateBase>(builder =>
                                                      builder
                                                      .WithArgumentsForConstructor(new object[]
                {
                    "test",
                    tracker.StateEnterAction,
                    tracker.StateExitAction,
                    tracker.StateCanceledAction,
                })
                                                      .CallsBaseMethods());

                A.CallTo(state)
                .Where(call => call.Method.Name == "ExecuteStepAsync")
                .WithReturnType <Task <RuntimeTransition> >()
                .Invokes(() => cts.Cancel());

                await Assert.ThrowsAsync <OperationCanceledException>(async() => await state.ExecuteAsync(cts.Token));
            }

            Assert.Equal(">test;!test;", tracker.ToString());
        }
Example #6
0
        public async Task ExecuteAsync_CanceledDuringExit_RunsEnterAndExitActionsAndThrowsOperationCanceledException()
        {
            var tracker = new TestTracker();

            using (var cts = new CancellationTokenSource())
            {
                var state = A.Fake <RuntimeStateBase>(builder =>
                                                      builder
                                                      .WithArgumentsForConstructor(new object[]
                {
                    "test",
                    tracker.StateEnterAction,
                    new Func <string, Task>(async s =>
                    {
                        await tracker.StateExitAction(s);
                        cts.Cancel();
                    }),
                    tracker.StateCanceledAction,
                })
                                                      .CallsBaseMethods());

                await Assert.ThrowsAsync <OperationCanceledException>(async() => await state.ExecuteAsync(cts.Token));
            }

            Assert.Equal(">test;<test;", tracker.ToString());
        }
Example #7
0
        public async Task ExecuteAsync_WithSelectedTransitionAndCanceled_RunsCanceledActionAndThrowsOperationCanceledException()
        {
            var tracker = new TestTracker();

            using (var cts = new CancellationTokenSource())
            {
                var state = new SwitchRuntimeState <int>(
                    "test",
                    tracker.StateEnterAction,
                    tracker.StateExitAction,
                    tracker.StateCanceledAction,
                    new RuntimeTransition("False", A.Fake <ITransitionTarget>(), null, null),
                    new Dictionary <int, RuntimeTransition>
                {
                    { 0, new RuntimeTransition("0", null, null, null) },
                    { 1, new RuntimeTransition("1", A.Fake <ITransitionTarget>(), null, null) },
                    { 2, new RuntimeTransition("2", null, null, null) },
                },
                    () =>
                {
                    cts.Cancel();
                    return(1);
                });

                await Assert.ThrowsAsync <OperationCanceledException>(async() => await state.ExecuteAsync(cts.Token));
            }

            Assert.Equal(">test;!test;", tracker.ToString());
        }
Example #8
0
        public async Task ExecuteAsync_WithSelectedTransitionAndCanceled_RunsCanceledActionAndThrowsOperationCanceledException()
        {
            var tracker = new TestTracker();

            using (var cts = new CancellationTokenSource())
            {
                var selectedTransition = new RuntimeTransition("Selected", A.Fake <ITransitionTarget>(), tracker.TransitionAction, null);
                var elseTransition     = new RuntimeTransition("Else", A.Fake <ITransitionTarget>(), tracker.TransitionAction, null);

                var state = A.Fake <ChoiceRuntimeStateBase>(builder =>
                                                            builder
                                                            .WithArgumentsForConstructor(new object[]
                {
                    "test",
                    tracker.StateEnterAction,
                    tracker.StateExitAction,
                    tracker.StateCanceledAction,
                    elseTransition,
                })
                                                            .CallsBaseMethods());

                A.CallTo(state)
                .Where(call => call.Method.Name == "SelectTransition")
                .WithReturnType <RuntimeTransition>()
                .ReturnsLazily(() =>
                {
                    cts.Cancel();
                    return(selectedTransition);
                });

                await Assert.ThrowsAsync <OperationCanceledException>(async() => await state.ExecuteAsync(cts.Token));
            }

            Assert.Equal(">test;!test;", tracker.ToString());
        }
Example #9
0
        public async Task ExecuteAsync_WithEventTransitionsNotCanceledWithTriggeredEventTransition_ReturnsEventTransitionAndAcknowledgesHandledEvent()
        {
            var tracker = new TestTracker();

            var eventName = "event";

            var eventTransition = new RuntimeTransition("Targeted", A.Fake <ITransitionTarget>(), tracker.TransitionAction, null);
            var stateTransition = new RuntimeTransition("State", A.Fake <ITransitionTarget>(), tracker.TransitionAction, null);

            var state = A.Fake <EventRuntimeStateBase>(
                x =>
            {
                x.WithArgumentsForConstructor(new object[]
                {
                    "test",
                    tracker.StateEnterAction,
                    tracker.StateExitAction,
                    tracker.StateCanceledAction,
                });

                x.CallsBaseMethods();
            });

            A.CallTo(state)
            .Where(call => call.Method.Name == "EnterStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .CallsBaseMethod();

            A.CallTo(state)
            .Where(call => call.Method.Name == "ExitStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .CallsBaseMethod();

            A.CallTo(state)
            .Where(call => call.Method.Name == "ExecuteEventStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .Returns(Task.FromResult <RuntimeTransition>(null))
            .Once();

            state.AddEventTransition(eventName, eventTransition);

            var executeTask = state.ExecuteAsync(CancellationToken.None);

            Assert.True(await state.PublishEventAsync(eventName));

            var actual = await executeTask;

            A.CallTo(state)
            .Where(call => call.Method.Name == "ExecuteEventStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .MustHaveHappened(Repeated.Exactly.Once);

            Assert.Equal(eventTransition, actual);
            Assert.Equal(">test;!test;", tracker.ToString());
        }
Example #10
0
        public async Task ExecuteAsync_WithEventTransitionsNotCanceledWithoutTriggeredEventTransitionAndStateExecutionReturningNull_DoesntCompleteExecution()
        {
            var tracker = new TestTracker();

            var eventName = "event";

            var eventTransition = new RuntimeTransition("Event", A.Fake <ITransitionTarget>(), tracker.TransitionAction, null);

            var stateMock = A.Fake <EventRuntimeStateBase>(
                x =>
            {
                x.WithArgumentsForConstructor(new object[]
                {
                    "test",
                    tracker.StateEnterAction,
                    tracker.StateExitAction,
                    tracker.StateCanceledAction,
                });

                x.CallsBaseMethods();
            });

            A.CallTo(stateMock)
            .Where(call => call.Method.Name == "EnterStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .CallsBaseMethod();

            A.CallTo(stateMock)
            .Where(call => call.Method.Name == "ExitStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .CallsBaseMethod();

            A.CallTo(stateMock)
            .Where(call => call.Method.Name == "ExecuteEventStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .Returns(Task.FromResult <RuntimeTransition>(null))
            .Once();

            stateMock.AddEventTransition(eventName, eventTransition);

            var executeTask = stateMock.ExecuteAsync(CancellationToken.None);

            A.CallTo(stateMock)
            .Where(call => call.Method.Name == "ExecuteEventStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .MustHaveHappened(Repeated.Exactly.Once);

            Assert.False(executeTask.IsCompleted);
            Assert.Equal(">test;", tracker.ToString());
        }
Example #11
0
        public async Task ExecuteAsync_WithoutTransitions_CompletesImmediatelly()
        {
            var tracker = new TestTracker();

            var state = new SimpleRuntimeState(
                "test",
                tracker.StateEnterAction,
                tracker.StateExecutionAction,
                tracker.StateExitAction,
                tracker.StateCanceledAction);

            await state.ExecuteAsync(CancellationToken.None);

            Assert.Equal(">test;*test;<test;", tracker.ToString());
        }
Example #12
0
        public async Task ExecuteAsync_WithoutEventTransitionsNotCanceled_ReturnsReturnValueOfExecuteEventStepAsync()
        {
            var tracker = new TestTracker();

            var stateTransition = new RuntimeTransition("Targeted", A.Fake <ITransitionTarget>(), tracker.TransitionAction, null);

            var stateMock = A.Fake <EventRuntimeStateBase>(
                x =>
            {
                x.WithArgumentsForConstructor(new object[]
                {
                    "test",
                    tracker.StateEnterAction,
                    tracker.StateExitAction,
                    tracker.StateCanceledAction,
                });

                x.CallsBaseMethods();
            });

            A.CallTo(stateMock)
            .Where(call => call.Method.Name == "EnterStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .CallsBaseMethod();

            A.CallTo(stateMock)
            .Where(call => call.Method.Name == "ExitStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .CallsBaseMethod();

            A.CallTo(stateMock)
            .Where(call => call.Method.Name == "ExecuteEventStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .Returns(Task.FromResult <RuntimeTransition>(stateTransition))
            .Once();

            var actual = await stateMock.ExecuteAsync(CancellationToken.None);

            A.CallTo(stateMock)
            .Where(call => call.Method.Name == "ExecuteEventStepAsync")
            .WithReturnType <Task <RuntimeTransition> >()
            .MustHaveHappened(Repeated.Exactly.Once);

            Assert.Equal(stateTransition, actual);
            Assert.Equal(">test;<test;", tracker.ToString());
        }
Example #13
0
        public async Task SimpleState_BuildRuntimeStateAndExecute()
        {
            var tracker = new TestTracker();

            var state = new SimpleState("test")
            {
                OnEnterAction    = tracker.StateEnterAction,
                OnExecuteAction  = tracker.StateExecutionAction,
                OnExitAction     = tracker.StateExitAction,
                OnCanceledAction = tracker.StateCanceledAction,
            };

            await state
            .BuildRuntimeState()
            .ExecuteAsync(CancellationToken.None);

            Assert.Equal(">test;*test;<test;", tracker.ToString());
        }
Example #14
0
        public async Task ExecuteAsync_WithoutCancellation_RunsEnterAndExitActions()
        {
            var tracker = new TestTracker();

            var state = A.Fake <RuntimeStateBase>(builder =>
                                                  builder.WithArgumentsForConstructor(new object[]
            {
                "test",
                tracker.StateEnterAction,
                tracker.StateExitAction,
                tracker.StateCanceledAction,
            })
                                                  .CallsBaseMethods());

            await state.ExecuteAsync(CancellationToken.None);

            Assert.Equal(">test;<test;", tracker.ToString());
        }
Example #15
0
        public async Task ExecuteAsync_WhenPredicateReturnsFalseAndCanceled_RunsCanceledActionAndThrowsOperationCanceledException()
        {
            var tracker = new TestTracker();

            using (var cts = new CancellationTokenSource())
            {
                var state = new IfElseRuntimeState(
                    "test",
                    tracker.StateEnterAction,
                    tracker.StateExitAction,
                    tracker.StateCanceledAction,
                    new RuntimeTransition("True", null, null, null),
                    new RuntimeTransition("False", null, null, null),
                    () =>
                {
                    cts.Cancel();
                    return(false);
                });

                await Assert.ThrowsAsync <OperationCanceledException>(async() => await state.ExecuteAsync(cts.Token));
            }

            Assert.Equal(">test;!test;", tracker.ToString());
        }
Example #16
0
        public async Task ExecuteAsync_CanceledBeforeExecution_RunsNodActionAndThrowsOperationCanceledException()
        {
            var tracker = new TestTracker();

            using (var cts = new CancellationTokenSource())
            {
                cts.Cancel();

                var state = A.Fake <RuntimeStateBase>(builder =>
                                                      builder
                                                      .WithArgumentsForConstructor(new object[]
                {
                    "test",
                    tracker.StateEnterAction,
                    tracker.StateExitAction,
                    tracker.StateCanceledAction,
                })
                                                      .CallsBaseMethods());

                await Assert.ThrowsAsync <OperationCanceledException>(async() => await state.ExecuteAsync(cts.Token));
            }

            Assert.Equal(string.Empty, tracker.ToString());
        }
Example #17
0
        public async Task CompositeRuntimeState_WithoutCancellationAndEventTransitions_ExecutesAllSubStates()
        {
            var tracker = new TestTracker();

            var tcs2 = new TaskCompletionSource <object>();

            var state1 = new SimpleRuntimeState(
                "state1",
                tracker.StateEnterAction,
                tracker.StateExecutionAction,
                tracker.StateExitAction,
                tracker.StateCanceledAction);

            var state2 = new SimpleRuntimeState(
                "state2",
                tracker.StateEnterAction,
                async s =>
            {
                await tracker.StateExecutionAction(s);
                tcs2.SetResult(null);
            },
                tracker.StateExitAction,
                tracker.StateCanceledAction);

            var state3 = new SimpleRuntimeState(
                "state3",
                tracker.StateEnterAction,
                tracker.StateExecutionAction,
                tracker.StateExitAction,
                tracker.StateCanceledAction);

            var compositeState = new CompositeRuntimeState(
                "composite",
                tracker.StateEnterAction,
                tracker.StateExitAction,
                tracker.StateCanceledAction,
                new RuntimeTransition("T1", state1, tracker.TransitionAction, null));

            state1.AddEventTransition("E1", new RuntimeTransition("T2", state2, tracker.TransitionAction, null));
            state2.AddEventTransition("E2", new RuntimeTransition("T3", state3, tracker.TransitionAction, null));

            var task = compositeState.ExecuteAsync(CancellationToken.None);

            Assert.False(task.IsCompleted);

            var handled = await compositeState.PublishEventAsync("E1");

            Assert.True(handled);
            Assert.False(task.IsCompleted);

            await tcs2.Task;

            handled = await compositeState.PublishEventAsync("E2");

            Assert.True(handled);

            await task;

            Assert.Equal(">composite;@composite->state1;>state1;*state1;!state1;@state1->state2;>state2;*state2;!state2;@state2->state3;>state3;*state3;<state3;<composite;", tracker.ToString());
        }
Example #18
0
        public async Task ParallelAllRuntimeState_WithoutCancellationAndEventTransitions_ExecutesAllSubStates()
        {
            var tracker = new TestTracker();

            var tcs1 = new TaskCompletionSource <object>(TaskCreationOptions.None);
            var tcs2 = new TaskCompletionSource <object>(TaskCreationOptions.None);
            var tcs3 = new TaskCompletionSource <object>(TaskCreationOptions.None);

            var state1 = new SimpleRuntimeState(
                "state1",
                tracker.StateEnterAction,
                async s =>
            {
                await tracker.StateExecutionAction(s);
                await tcs1.Task;
            },
                tracker.StateExitAction,
                tracker.StateCanceledAction);

            var state2 = new SimpleRuntimeState(
                "state2",
                tracker.StateEnterAction,
                async s =>
            {
                await tracker.StateExecutionAction(s);
                await tcs2.Task;
            },
                tracker.StateExitAction,
                tracker.StateCanceledAction);

            var state3 = new SimpleRuntimeState(
                "state3",
                tracker.StateEnterAction,
                async s =>
            {
                await tracker.StateExecutionAction(s);
                await tcs3.Task;
            },
                tracker.StateExitAction,
                tracker.StateCanceledAction);

            var parallelState = new ParallelAllRuntimeState(
                "parallel",
                tracker.StateEnterAction,
                tracker.StateExitAction,
                tracker.StateCanceledAction,
                new RuntimeStateBase[] { state1, state2, state3 });

            var task = parallelState.ExecuteAsync(CancellationToken.None);

            tcs2.TrySetResult(null);
            tcs3.TrySetResult(null);
            tcs1.TrySetResult(null);

            await task;

            var tracking = tracker.ToString();

            Assert.EndsWith("<parallel;", tracking);

            var endingIndex = tracking.IndexOf("<");

            Assert.True(tracking.IndexOf("<state1;", endingIndex) > 0);
            Assert.True(tracking.IndexOf("<state2;", endingIndex) > 0);
            Assert.True(tracking.IndexOf("<state3;", endingIndex) > 0);
        }