public SimpleStateMachine() { var builder = new StateMachineDefinitionBuilder <States, Events>(); builder .In(States.Off) .On(Events.TurnOn) .Goto(States.On) .Execute(SayHello); builder .In(States.On) .On(Events.TurnOff) .Goto(States.Off) .Execute(SayBye); builder .WithInitialState(States.Off); machine = builder .Build() .CreatePassiveStateMachine(); machine.Start(); }
public void SetsCurrentStateOnLoadingFromPersistedState(string dummyName, Func <StateMachineDefinition <States, Events>, IStateMachine <States, Events> > createStateMachine) { var loader = A.Fake <IStateMachineLoader <States> >(); var extension = A.Fake <IExtension <States, Events> >(); A.CallTo(() => loader.LoadCurrentState()) .Returns(Initializable <States> .Initialized(States.C)); var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <States, Events>(); stateMachineDefinitionBuilder .In(States.A); stateMachineDefinitionBuilder .In(States.C); var stateMachineDefinition = stateMachineDefinitionBuilder .WithInitialState(States.A) .Build(); var testee = createStateMachine(stateMachineDefinition); testee.AddExtension(extension); testee.Load(loader); A.CallTo(() => extension.Loaded( A <IStateMachineInformation <States, Events> > .Ignored, A <Initializable <States> > .That .Matches(currentState => currentState.IsInitialized && currentState.ExtractOrThrow() == States.C), A <IReadOnlyDictionary <States, States> > .Ignored)) .MustHaveHappenedOnceExactly(); }
public void EventsQueueing( IStateMachine <string, int> machine, AutoResetEvent signal) { const int FirstEvent = 0; const int SecondEvent = 1; "establish an active state machine with transitions".x(() => { signal = new AutoResetEvent(false); var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <string, int>(); stateMachineDefinitionBuilder.In("A").On(FirstEvent).Goto("B"); stateMachineDefinitionBuilder.In("B").On(SecondEvent).Goto("C"); stateMachineDefinitionBuilder.In("C").ExecuteOnEntry(() => signal.Set()); machine = stateMachineDefinitionBuilder .WithInitialState("A") .Build() .CreateActiveStateMachine(); }); "when firing an event onto the state machine".x(() => { machine.Fire(FirstEvent); machine.Fire(SecondEvent); machine.Start(); }); "it should queue event at the end".x(() => signal .WaitOne(1000) .Should() .BeTrue("state machine should arrive at destination state")); }
private StateMachineDefinitionBuilder <EnrolleeState, SubmissionAction> InitBuilder() { var builder = new StateMachineDefinitionBuilder <EnrolleeState, SubmissionAction>(); builder.In(EnrolleeState.Editable) .On(SubmissionAction.LockProfile).If <bool>(isAdmin => isAdmin).Execute(HandleLockProfile) .On(SubmissionAction.DeclineProfile).If <bool>(isAdmin => isAdmin).Execute(HandleDeclineProfile); builder.In(EnrolleeState.UnderReview) .On(SubmissionAction.Approve).If <bool>(isAdmin => isAdmin).Execute(HandleApprove) .On(SubmissionAction.EnableEditing).If <bool>(isAdmin => isAdmin).Execute(HandleEnableEditing) .On(SubmissionAction.LockProfile).If <bool>(isAdmin => isAdmin).Execute(HandleLockProfile) .On(SubmissionAction.DeclineProfile).If <bool>(isAdmin => isAdmin).Execute(HandleDeclineProfile) .On(SubmissionAction.RerunRules).If <bool>(isAdmin => isAdmin).Execute(HandleRerunRules); builder.In(EnrolleeState.RequiresToa) .On(SubmissionAction.AcceptToa).If <bool>(isAdmin => !isAdmin).Execute(HandleAcceptToa) .On(SubmissionAction.DeclineToa).If <bool>(isAdmin => !isAdmin).Execute(HandleDeclineToa) .On(SubmissionAction.EnableEditing).If <bool>(isAdmin => isAdmin).Execute(HandleEnableEditing) .On(SubmissionAction.LockProfile).If <bool>(isAdmin => isAdmin).Execute(HandleLockProfile) .On(SubmissionAction.DeclineProfile).If <bool>(isAdmin => isAdmin).Execute(HandleDeclineProfile); builder.In(EnrolleeState.Locked) .On(SubmissionAction.EnableEditing).If <bool>(isAdmin => isAdmin).Execute(HandleEnableEditing) .On(SubmissionAction.DeclineProfile).If <bool>(isAdmin => isAdmin).Execute(HandleDeclineProfile); builder.In(EnrolleeState.Declined) .On(SubmissionAction.EnableProfile).If <bool>(isAdmin => isAdmin).Execute(HandleEnableEditing); return(builder); }
public void EntryActionException(PassiveStateMachine <int, int> machine) { "establish an entry action throwing an exception".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(Values.Source) .On(Values.Event) .Goto(Values.Destination); stateMachineDefinitionBuilder .In(Values.Destination) .ExecuteOnEntry(() => throw Values.Exception); machine = stateMachineDefinitionBuilder .WithInitialState(Values.Source) .Build() .CreatePassiveStateMachine(); machine.TransitionExceptionThrown += (s, e) => this.receivedTransitionExceptionEventArgs = e; }); "when executing the transition".x(() => { machine.Start(); machine.Fire(Values.Event, Values.Parameter); }); this.ItShouldHandleTransitionException(); }
private StateMachineDefinitionBuilder <EnrolleeState, SubmissionAction> InitBuilder() { var builder = new StateMachineDefinitionBuilder <EnrolleeState, SubmissionAction>(); builder.In(EnrolleeState.Editable) .On(SubmissionAction.LockProfile).IfAdmin(AllowAction) .On(SubmissionAction.DeclineProfile).IfAdmin(AllowAction); builder.In(EnrolleeState.UnderReview) .On(SubmissionAction.Approve).IfAdmin(AllowAction) .On(SubmissionAction.EnableEditing).IfAdmin(AllowAction) .On(SubmissionAction.LockProfile).IfAdmin(AllowAction) .On(SubmissionAction.DeclineProfile).IfAdmin(AllowAction) .On(SubmissionAction.RerunRules).IfAdmin(AllowAction); builder.In(EnrolleeState.RequiresToa) .On(SubmissionAction.AcceptToa).IfEnrollee(AllowAction) .On(SubmissionAction.DeclineToa).IfEnrollee(AllowAction) .On(SubmissionAction.EnableEditing).IfAdmin(AllowAction) .On(SubmissionAction.LockProfile).IfAdmin(AllowAction) .On(SubmissionAction.DeclineProfile).IfAdmin(AllowAction); builder.In(EnrolleeState.Locked) .On(SubmissionAction.EnableEditing).IfAdmin(AllowAction) .On(SubmissionAction.DeclineProfile).IfAdmin(AllowAction); builder.In(EnrolleeState.Declined) .On(SubmissionAction.EnableEditing).IfAdmin(AllowAction); return(builder); }
public void EventsQueueing( IStateMachine <string, int> machine) { const int FirstEvent = 0; const int SecondEvent = 1; var arrived = false; "establish a passive state machine with transitions".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <string, int>(); stateMachineDefinitionBuilder.In("A").On(FirstEvent).Goto("B"); stateMachineDefinitionBuilder.In("B").On(SecondEvent).Goto("C"); stateMachineDefinitionBuilder.In("C").ExecuteOnEntry(() => arrived = true); machine = stateMachineDefinitionBuilder .WithInitialState("A") .Build() .CreatePassiveStateMachine(); }); "when firing an event onto the state machine".x(() => { machine.Fire(FirstEvent); machine.Fire(SecondEvent); machine.Start(); }); "it should queue event at the end".x(() => arrived .Should() .BeTrue("state machine should arrive at destination state")); }
public void EventArgument( PassiveStateMachine <int, int> machine, int passedArgument) { const int Argument = 17; "establish a state machine with an exit action taking an event argument".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(State) .ExecuteOnExit((int argument) => passedArgument = argument) .On(Event).Goto(AnotherState); stateMachineDefinitionBuilder .In(AnotherState) .ExecuteOnEntry((int argument) => passedArgument = argument); machine = stateMachineDefinitionBuilder .WithInitialState(State) .Build() .CreatePassiveStateMachine(); }); "when leaving the state".x(() => { machine.Start(); machine.Fire(Event, Argument); }); "it should pass event argument to exit action".x(() => passedArgument.Should().Be(Argument)); }
public void CustomTypesForStatesAndEvents( AsyncPassiveStateMachine <MyState, MyEvent> machine, bool arrivedInStateB) { "establish a state machine with custom types for states and events".x(async() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <MyState, MyEvent>(); stateMachineDefinitionBuilder .In(new MyState("A")) .On(new MyEvent(1)).Goto(new MyState("B")); stateMachineDefinitionBuilder .In(new MyState("B")) .ExecuteOnEntry(() => arrivedInStateB = true); machine = stateMachineDefinitionBuilder .WithInitialState(new MyState("A")) .Build() .CreatePassiveStateMachine(); await machine.Start(); }); "when using the state machine".x(() => machine.Fire(new MyEvent(1))); "it should use equals to compare states and events".x(() => arrivedInStateB.Should().BeTrue("state B should be current state")); }
public void InitialStateSetViaDefinitionBuilder() { var stateMachineSaver = new StateMachineSaver <string>(); var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <string, int>(); stateMachineDefinitionBuilder .In("A") .On(1) .Goto("B"); stateMachineDefinitionBuilder .In("B") .On(2) .Goto("C"); stateMachineDefinitionBuilder .WithInitialState("A"); var machine = stateMachineDefinitionBuilder .Build() .CreatePassiveStateMachine(); machine.Start(); machine.Fire(1); machine.Save(stateMachineSaver); stateMachineSaver .CurrentStateId .Should() .Match <Initializable <string> >(currentState => currentState.IsInitialized && currentState.ExtractOrThrow() == "B"); }
public void CommonAncestor( AsyncPassiveStateMachine <int, int> machine) { const int commonAncestorState = 0; const int sourceState = 1; const int parentOfSourceState = 2; const int siblingOfSourceState = 3; const int destinationState = 4; const int parentOfDestinationState = 5; const int siblingOfDestinationState = 6; const int Event = 0; var commonAncestorStateLeft = false; "establish a hierarchical state machine".x(async() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .DefineHierarchyOn(commonAncestorState) .WithHistoryType(HistoryType.None) .WithInitialSubState(parentOfSourceState) .WithSubState(parentOfDestinationState); stateMachineDefinitionBuilder .DefineHierarchyOn(parentOfSourceState) .WithHistoryType(HistoryType.None) .WithInitialSubState(sourceState) .WithSubState(siblingOfSourceState); stateMachineDefinitionBuilder .DefineHierarchyOn(parentOfDestinationState) .WithHistoryType(HistoryType.None) .WithInitialSubState(destinationState) .WithSubState(siblingOfDestinationState); stateMachineDefinitionBuilder .In(sourceState) .On(Event).Goto(destinationState); stateMachineDefinitionBuilder .In(commonAncestorState) .ExecuteOnExit(() => commonAncestorStateLeft = true); machine = stateMachineDefinitionBuilder .WithInitialState(sourceState) .Build() .CreatePassiveStateMachine(); await machine.Start(); }); "when firing an event resulting in a transition with a common ancestor".x(() => machine.Fire(Event)); "the state machine should remain inside common ancestor state".x(() => commonAncestorStateLeft .Should().BeFalse()); }
public void SavingEventsForActiveStateMachine( AsyncActiveStateMachine <string, int> machine, StateMachineSaver <string, int> saver) { "establish a state machine".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <string, int>(); stateMachineDefinitionBuilder .In("A") .On(1) .Goto("B"); stateMachineDefinitionBuilder .In("B") .On(2) .Goto("C"); stateMachineDefinitionBuilder .In("C") .On(3) .Goto("A"); machine = stateMachineDefinitionBuilder .WithInitialState("A") .Build() .CreateActiveStateMachine(); }); "when events are fired".x(async() => { await machine.Fire(1); await machine.Fire(2); await machine.FirePriority(3); await machine.FirePriority(4); }); "and it is saved".x(async() => { saver = new StateMachineSaver <string, int>(); await machine.Save(saver); }); "it should save those events".x(() => { saver .Events .Select(x => x.EventId) .Should() .HaveCount(2) .And .ContainInOrder(1, 2); saver .PriorityEvents .Select(x => x.EventId) .Should() .HaveCount(2) .And .ContainInOrder(4, 3); }); }
public void LoadingEvents( PassiveStateMachine <string, int> machine) { "establish a state machine".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <string, int>(); stateMachineDefinitionBuilder .In("A") .On(1) .Goto("B"); stateMachineDefinitionBuilder .In("B") .On(2) .Goto("C"); stateMachineDefinitionBuilder .In("C") .On(3) .Goto("A"); machine = stateMachineDefinitionBuilder .WithInitialState("A") .Build() .CreatePassiveStateMachine(); }); "when it is loaded with Events".x(() => { var loader = new StateMachineLoader <string, int>(); loader.SetEvents(new List <EventInformation <int> > { new EventInformation <int>(1, null), new EventInformation <int>(2, null), }); machine.Load(loader); }); "it should process those events".x(() => { var transitionRecords = new List <TransitionRecord>(); machine.TransitionCompleted += (sender, args) => transitionRecords.Add( new TransitionRecord(args.EventId, args.StateId, args.NewStateId)); machine.Start(); transitionRecords .Should() .HaveCount(2) .And .IsEquivalentInOrder(new List <TransitionRecord> { new TransitionRecord(1, "A", "B"), new TransitionRecord(2, "B", "C") }); }); }
public Elevator() { var builder = new StateMachineDefinitionBuilder <States, Events>(); builder.DefineHierarchyOn(States.Healthy) .WithHistoryType(HistoryType.Deep) .WithInitialSubState(States.OnFloor) .WithSubState(States.Moving); builder.DefineHierarchyOn(States.Moving) .WithHistoryType(HistoryType.Shallow) .WithInitialSubState(States.MovingUp) .WithSubState(States.MovingDown); builder.DefineHierarchyOn(States.OnFloor) .WithHistoryType(HistoryType.None) .WithInitialSubState(States.DoorClosed) .WithSubState(States.DoorOpen); builder.In(States.Healthy) .ExecuteOnEntry(() => { }) .On(Events.Error).Goto(States.Error); builder.In(States.Error) .On(Events.Reset).Goto(States.Healthy) .On(Events.Error); builder.In(States.OnFloor) .ExecuteOnEntry(this.AnnounceFloor) .ExecuteOnExit(Beep) .ExecuteOnExit(Beep) // just beep a second time .On(Events.CloseDoor).Goto(States.DoorClosed) .On(Events.OpenDoor).Goto(States.DoorOpen) .On(Events.GoUp) .If(CheckOverload).Goto(States.MovingUp) .Otherwise().Execute(this.AnnounceOverload) .On(Events.GoDown) .If(CheckOverload).Goto(States.MovingDown) .Otherwise().Execute(this.AnnounceOverload); builder.In(States.Moving) .On(Events.Stop).Goto(States.OnFloor); builder.WithInitialState(States.OnFloor); var definition = builder .Build(); elevator = definition .CreatePassiveStateMachine("Elevator"); elevator.Start(); }
public void PriorityFire(string dummyName, Func <StateMachineDefinition <States, Events>, IStateMachine <States, Events> > createStateMachine) { const int Transitions = 3; var exceptions = new List <EventArgs>(); var transitionCompletedMessages = new List <TransitionCompletedEventArgs <States, Events> >(); var transitionDeclinedMessages = new List <TransitionEventArgs <States, Events> >(); IStateMachine <States, Events> testee = null; var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <States, Events>(); stateMachineDefinitionBuilder .In(States.A) .On(Events.B).Goto(States.B).Execute(() => { FireD(); FirePriorityC(); }); stateMachineDefinitionBuilder .In(States.B) .On(Events.C).Goto(States.C); stateMachineDefinitionBuilder .In(States.C) .On(Events.D).Goto(States.D); var stateMachineDefinition = stateMachineDefinitionBuilder .WithInitialState(States.A) .Build(); testee = createStateMachine(stateMachineDefinition); void FireD() => testee.Fire(Events.D); void FirePriorityC() => testee.FirePriority(Events.C); testee.TransitionExceptionThrown += (sender, e) => exceptions.Add(e); testee.TransitionCompleted += (sender, e) => transitionCompletedMessages.Add(e); testee.TransitionDeclined += (sender, e) => transitionDeclinedMessages.Add(e); var allTransitionsCompleted = SetUpWaitForAllTransitions(testee, 1); testee.Start(); testee.Fire(Events.B); WaitForAllTransitions(allTransitionsCompleted); transitionCompletedMessages.Count.Should().Be(Transitions); transitionDeclinedMessages.Should().BeEmpty(); exceptions.Should().BeEmpty(); testee.Stop(); }
private void startFSM(FSMConfiguration fsmConfiguration) { mainFSMConfiguration = fsmConfiguration; fSMData.tcaTSLPath = fsmConfiguration.tslPath; fSMData.comPortName = fsmConfiguration.defaultComPortName; fSMData.ruSerialPort = new RuSerialPort(); fSMData.tCACommand = new TCAControl.TCACommandWarpper(fSMData.tcaTSLPath); proxyRunMachine = new StateMachineDefinitionBuilder <States, Events>(); proxyRunMachine.WithInitialState(States.Connncted); proxyRunMachine.In(States.Connncted).On(Events.CT11Command).Goto(States.CT11Mode).Execute(ct11Mode); proxyRunMachine.In(States.Connncted).On(Events.RuCommand).Goto(States.RuMode).Execute(ruMode); proxyRunMachine.In(States.Connncted).On(Events.TCAIcolishCommand).Goto(States.TCAIcolishMode).Execute(tCAIcolishMode); proxyRunMachine.In(States.TCAIcolishMode).On(Events.GoBack).Goto(States.Connncted).Execute(connected); proxyRunMachine.In(States.CT11Mode).On(Events.RuCommand).Goto(States.RuMode).Execute(ruMode); proxyRunMachine.In(States.CT11Mode).On(Events.GoBack).Goto(States.Connncted).Execute(connected); proxyRunMachine.In(States.RuMode).On(Events.CT11Command).Goto(States.CT11Mode).Execute(ct11Mode); proxyRunMachine.In(States.RuMode).On(Events.GoBack).Goto(States.Connncted).Execute(connected); var definition = proxyRunMachine.Build(); fSMData.elevator = definition.CreateActiveStateMachine(); fSMData.elevator.Start(); //Action must Instantiate after FSM member Instantiate connectedAction = new ConnectedAction(ref fSMData); ruModeAction = new RuModeAction(ref fSMData); ct11ModeAction = new CT11ModeAction(ref fSMData); tCAIcolishAction = new TCAIcolishAction(ref fSMData); }
public void BeforeExecutingEntryActions( AsyncPassiveStateMachine <string, int> machine, IExtension <string, int> extension) { "establish an extension".x(() => extension = A.Fake <IExtension <string, int> >()); "establish a state machine using the extension".x(async() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <string, int>(); stateMachineDefinitionBuilder .In("0") .On(1) .Goto("1"); machine = stateMachineDefinitionBuilder .WithInitialState("0") .Build() .CreatePassiveStateMachine(Name); machine.AddExtension(extension); await machine.Start(); }); "when firing an event onto the state machine".x(() => machine.Fire(1)); "it should call EnteringState on registered extensions for target state".x(() => A.CallTo(() => extension.EnteringState( A <IStateMachineInformation <string, int> > .That.Matches(x => x.Name == Name && x.CurrentStateId.ExtractOrThrow() == "1"), A <IStateDefinition <string, int> > .That.Matches(x => x.Id == "1"), A <ITransitionContext <string, int> > .That.Matches(x => x.EventId.Value == 1))) .MustHaveHappened()); }
public void EntryAction( AsyncPassiveStateMachine <int, int> machine, bool entryActionExecuted, bool asyncEntryActionExecuted) { "establish a state machine with entry action on a state".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(State) .ExecuteOnEntry(() => entryActionExecuted = true) .ExecuteOnEntry(async() => { asyncEntryActionExecuted = true; await Task.Yield(); }); machine = stateMachineDefinitionBuilder .WithInitialState(State) .Build() .CreatePassiveStateMachine(); }); "when entering the state".x(async() => await machine.Start()); "it should execute the synchronous entry action".x(() => entryActionExecuted.Should().BeTrue()); "it should execute the asynchronous entry action".x(() => asyncEntryActionExecuted.Should().BeTrue()); }
public void ExitAction( PassiveStateMachine <int, int> machine, bool exitActionExecuted) { "establish a state machine with exit action on a state".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(State) .ExecuteOnExit(() => exitActionExecuted = true) .On(Event).Goto(AnotherState); machine = stateMachineDefinitionBuilder .WithInitialState(State) .Build() .CreatePassiveStateMachine(); }); "when leaving the state".x(() => { machine.Start(); machine.Fire(Event); }); "it should execute the exit action".x(() => exitActionExecuted.Should().BeTrue()); }
public void MatchingGuard( AsyncPassiveStateMachine <int, int> machine, CurrentStateExtension currentStateExtension) { "establish a state machine with guarded transitions".x(async() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(SourceState) .On(Event) .If(() => false).Goto(ErrorState) .If(async() => await Task.FromResult(false)).Goto(ErrorState) .If(async() => await Task.FromResult(true)).Goto(DestinationState) .If(() => true).Goto(ErrorState) .Otherwise().Goto(ErrorState); machine = stateMachineDefinitionBuilder .WithInitialState(SourceState) .Build() .CreatePassiveStateMachine(); currentStateExtension = new CurrentStateExtension(); machine.AddExtension(currentStateExtension); await machine.Start(); }); "when an event is fired".x(() => machine.Fire(Event)); "it should take transition guarded with first matching guard".x(() => currentStateExtension.CurrentState.Should().Be(DestinationState)); }
public void NoMatchingGuard( AsyncPassiveStateMachine <int, int> machine) { var declined = false; "establish state machine with no matching guard".x(async() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(SourceState) .On(Event) .If(() => Task.FromResult(false)).Goto(ErrorState); machine = stateMachineDefinitionBuilder .WithInitialState(SourceState) .Build() .CreatePassiveStateMachine(); var currentStateExtension = new CurrentStateExtension(); machine.AddExtension(currentStateExtension); machine.TransitionDeclined += (sender, e) => declined = true; await machine.Start(); }); "when an event is fired".x(() => machine.Fire(Event)); "it should notify about declined transition".x(() => declined.Should().BeTrue("TransitionDeclined event should be fired")); }
public void OtherwiseGuard( AsyncPassiveStateMachine <int, int> machine, CurrentStateExtension currentStateExtension) { "establish a state machine with otherwise guard and no machting other guard".x(async() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(SourceState) .On(Event) .If(() => Task.FromResult(false)).Goto(ErrorState) .Otherwise().Goto(DestinationState); machine = stateMachineDefinitionBuilder .WithInitialState(SourceState) .Build() .CreatePassiveStateMachine(); currentStateExtension = new CurrentStateExtension(); machine.AddExtension(currentStateExtension); await machine.Start(); }); "when an event is fired".x(() => machine.Fire(Event)); "it should_take_transition_guarded_with_otherwise".x(() => currentStateExtension.CurrentState.Should().Be(DestinationState)); }
public void ExitActionWithParameter( PassiveStateMachine <int, int> machine, string parameter) { const string Parameter = "parameter"; "establish a state machine with exit action with parameter on a state".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(State) .ExecuteOnExitParametrized(p => parameter = p, Parameter) .On(Event).Goto(AnotherState); machine = stateMachineDefinitionBuilder .WithInitialState(State) .Build() .CreatePassiveStateMachine(); }); "when leaving the state".x(() => { machine.Start(); machine.Fire(Event); }); "it should execute the exit action".x(() => parameter.Should().NotBeNull()); "it should pass parameter to the exit action".x(() => parameter.Should().Be(Parameter)); }
public void MultipleExitActions( PassiveStateMachine <int, int> machine, bool exitAction1Executed, bool exitAction2Executed) { "establish a state machine with several exit actions on a state".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(State) .ExecuteOnExit(() => exitAction1Executed = true) .ExecuteOnExit(() => exitAction2Executed = true) .On(Event).Goto(AnotherState); machine = stateMachineDefinitionBuilder .WithInitialState(State) .Build() .CreatePassiveStateMachine(); }); "when leaving the state".x(() => { machine.Start(); machine.Fire(Event); }); "It should execute all exit actions".x(() => { exitAction1Executed .Should().BeTrue("first action should be executed"); exitAction2Executed .Should().BeTrue("second action should be executed"); }); }
public void GuardException(AsyncPassiveStateMachine <int, int> machine) { "establish a guard throwing an exception".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(Values.Source) .On(Values.Event) .If((Func <Task <bool> >)(() => throw Values.Exception)) .Goto(Values.Destination); machine = stateMachineDefinitionBuilder .WithInitialState(Values.Source) .Build() .CreatePassiveStateMachine(); machine.TransitionExceptionThrown += (s, e) => this.receivedTransitionExceptionEventArgs = e; }); "when executing the transition".x(async() => { await machine.Start(); await machine.Fire(Values.Event, Values.Parameter); }); this.ItShouldHandleTransitionException(); }
public void LoadingAnInitializedStateMachine( IAsyncStateMachine <string, int> machine, Exception receivedException) { "establish an started state machine".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <string, int>(); stateMachineDefinitionBuilder.In("initial"); machine = stateMachineDefinitionBuilder .WithInitialState("initial") .Build() .CreatePassiveStateMachine(); machine.Start(); }); "when state machine is loaded".x(async() => receivedException = await Catch.Exception(async() => await machine.Load(A.Fake <IAsyncStateMachineLoader <string> >()))); "it should throw invalid operation exception".x(() => { receivedException.Should().BeOfType <InvalidOperationException>(); receivedException.Message.Should().Be(ExceptionMessages.StateMachineIsAlreadyInitialized); }); }
public void Start( AsyncPassiveStateMachine <int, int> machine, bool entryActionExecuted, CurrentStateExtension currentStateExtension) { "establish an initialized state machine".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(TestState) .ExecuteOnEntry(() => entryActionExecuted = true); machine = stateMachineDefinitionBuilder .WithInitialState(TestState) .Build() .CreatePassiveStateMachine(); currentStateExtension = new CurrentStateExtension(); machine.AddExtension(currentStateExtension); }); "when starting the state machine".x(() => machine.Start()); "should set current state of state machine to state to which it is initialized".x(() => currentStateExtension.CurrentState.Should().Be(TestState)); "should execute entry action of state to which state machine is initialized".x(() => entryActionExecuted.Should().BeTrue()); }
public void StartingException(PassiveStateMachine <int, int> machine) { const int State = 1; "establish a entry action for the initial state that throws an exception".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(State) .ExecuteOnEntry(() => throw Values.Exception); machine = stateMachineDefinitionBuilder .WithInitialState(State) .Build() .CreatePassiveStateMachine(); machine.TransitionExceptionThrown += (s, e) => this.receivedTransitionExceptionEventArgs = e; }); "when starting the state machine".x(() => machine.Start()); "should catch exception and fire transition exception event".x(() => this.receivedTransitionExceptionEventArgs.Exception.Should().NotBeNull()); "should pass thrown exception to event arguments of transition exception event".x(() => this.receivedTransitionExceptionEventArgs.Exception.Should().BeSameAs(Values.Exception)); }
public void ClearingExtensions( IStateMachine <string, int> machine, IExtension <string, int> extension) { "establish a state machine with an extension".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <string, int>(); stateMachineDefinitionBuilder.In("initial"); machine = stateMachineDefinitionBuilder .WithInitialState("initial") .Build() .CreatePassiveStateMachine(); extension = A.Fake <IExtension <string, int> >(); machine.AddExtension(extension); }); "when clearing all extensions from the state machine".x(() => { machine.ClearExtensions(); machine.Start(); }); "it should not anymore notify extension about internal events".x(() => A.CallTo(extension) .MustNotHaveHappened()); }
public void NoExceptionHandlerRegistered( PassiveStateMachine <int, int> machine, Exception catchedException) { "establish an exception throwing state machine without a registered exception handler".x(() => { var stateMachineDefinitionBuilder = new StateMachineDefinitionBuilder <int, int>(); stateMachineDefinitionBuilder .In(Values.Source) .On(Values.Event) .Execute(() => throw Values.Exception); machine = stateMachineDefinitionBuilder .WithInitialState(Values.Source) .Build() .CreatePassiveStateMachine(); machine.Start(); }); "when an exception occurs".x(() => catchedException = Catch.Exception(() => machine.Fire(Values.Event))); "should (re-)throw exception".x(() => catchedException.InnerException .Should().BeSameAs(Values.Exception)); }