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()); }
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()); } }
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()); }
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()); }
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()); }
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()); }
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()); }
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()); }
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()); }
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()); }
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()); }
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()); }
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()); }
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()); }
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()); }
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()); }
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()); }
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); }