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 static RuntimeStateBase BuildRuntimeState(this StateBase state, IEnumerable <RuntimeStateBase> runtimeStates) { if (state == null) { throw new ArgumentNullException(nameof(state)); } var validation = state.Validate(); if (validation.Any()) { throw new ValidationException(validation); } switch (state) { case IfElseState ifElseState: return(new IfElseRuntimeState( ifElseState.Name, ifElseState.OnEnterAction, ifElseState.OnExitAction, ifElseState.OnCanceledAction, BuildRuntimeTransition(ifElseState.ElseTransition, runtimeStates), BuildRuntimeTransition(ifElseState.TrueTransition, runtimeStates), ifElseState.Predicate)); case ChoiceStateBase switchState when TryBuildSwitch(switchState, runtimeStates, out var runtimeState): return(runtimeState); case SimpleState simpleState: return(new SimpleRuntimeState( simpleState.Name, simpleState.OnEnterAction, simpleState.OnExecuteAction, simpleState.OnExitAction, simpleState.OnCanceledAction)); case CompositeState compositeState: var subStates = compositeState.SubStates.Select(s => BuildRuntimeState(s)).ToList(); var compositeRuntimeState = new CompositeRuntimeState( compositeState.Name, compositeState.OnEnterAction, compositeState.OnExitAction, compositeState.OnCanceledAction, BuildRuntimeTransition(compositeState.InitialTransition, subStates)); foreach (var pair in compositeState.Transitions) { foreach (var transition in pair.Value) { compositeRuntimeState.AddEventTransition(pair.Key, BuildRuntimeTransition(transition, subStates)); } } return(compositeRuntimeState); case ParallelState parallelState when parallelState.Mode == ParallelModes.All: return(new ParallelAllRuntimeState( parallelState.Name, parallelState.OnEnterAction, parallelState.OnExitAction, parallelState.OnCanceledAction, parallelState.Regions.Select(r => BuildRuntimeState(r)))); case ParallelState parallelState when parallelState.Mode == ParallelModes.Any: return(new ParallelAnyRuntimeState( parallelState.Name, parallelState.OnEnterAction, parallelState.OnExitAction, parallelState.OnCanceledAction, parallelState.Regions.Select(r => BuildRuntimeState(r)))); default: throw new ArgumentOutOfRangeException(nameof(state), $"Invalid state type: {state.GetType().FullName}"); } }