public void CurrentChildStateReflectsCurrentStateOfChild() { var sm = new StateMachine("state machine"); var initialState = sm.CreateInitialState("initial state"); var state1 = sm.CreateState("state1"); var childSm = state1.CreateChildStateMachine(); var childInitialState = childSm.CreateInitialState("childInitialState"); var childState1 = childSm.CreateState("childState1"); var evt = new Event("evt"); var evt2 = new Event("evt2"); initialState.TransitionOn(evt).To(state1); childInitialState.TransitionOn(evt).To(childState1); state1.TransitionOn(evt2).To(initialState); Assert.AreEqual(initialState, sm.CurrentChildState); evt.Fire(); Assert.AreEqual(childInitialState, sm.CurrentChildState); evt.Fire(); Assert.AreEqual(childState1, sm.CurrentChildState); evt2.Fire(); Assert.AreEqual(initialState, sm.CurrentChildState); }
public void ForcefullyTransitioningFromChildStateMachineCallsExitHandlerOnCurrentState() { StateHandlerInfo<State> state22ExitInfo = null; var sm = new StateMachine("State Machine"); var evt1 = new Event("Event 1"); var state1 = sm.CreateInitialState("State 1"); var state2 = sm.CreateState("State 2"); var subSm = state2.CreateChildStateMachine(); var state21 = subSm.CreateInitialState("State 2.1"); var state22 = subSm.CreateState("State 2.2").WithExit(i => state22ExitInfo = i); state1.TransitionOn(evt1).To(state2); state21.TransitionOn(evt1).To(state22); // Enter state2, and start child state machine evt1.Fire(); // Enter State 2.2 evt1.Fire(); // Transition from state2 to state1, exiting the child state machine sm.ForceTransition(state1, evt1); Assert.NotNull(state22ExitInfo); Assert.AreEqual(state22, state22ExitInfo.From); Assert.AreEqual(state1, state22ExitInfo.To); Assert.AreEqual(evt1, state22ExitInfo.Event); }
public void NoEventsAreQueuedIfAGuardThrowsAnException() { var sm = new StateMachine("sm"); var state1 = sm.CreateInitialState("state1"); var state2 = sm.CreateState("state2"); var evt = new Event("evt"); var evt2 = new Event("evt2"); var exception = new Exception("foo"); state1.TransitionOn(evt).To(state2).WithGuard(i => { evt.Fire(); throw exception; }); state1.TransitionOn(evt2).To(state2); state2.TransitionOn(evt).To(state1); Assert.Throws<Exception>(() => evt.Fire()); // Make sure that an event wasn't queued evt2.Fire(); Assert.AreEqual(state2, sm.CurrentState); }
public void CancellationTokenCancelsOperation() { var sm = new StateMachine("sm"); var initial = sm.CreateInitialState("initial"); var doingOperation = sm.CreateState("doingOperation"); var completedOperation = sm.CreateState("completedOperation"); var evt = new Event("evt"); initial.TransitionOn(evt).To(doingOperation); doingOperation.TransitionOn(evt).To(completedOperation); var cts = new CancellationTokenSource(); var op = new Operation<State>(evt, doingOperation, completedOperation); var task = op.TryFireAsync(cts.Token); Assert.False(task.IsCompleted); Assert.False(task.IsCanceled); cts.Cancel(); Assert.True(task.IsCanceled); // Check nothing explodes evt.Fire(); }
public void ResetResetsStateOfChildStateMachines() { var parent = new StateMachine("parent"); var initialState = parent.CreateInitialState("initialState"); var state1 = parent.CreateState("state1"); var child = state1.CreateChildStateMachine(); var substate1 = child.CreateInitialState("substate1"); var substate2 = child.CreateState("substate2"); var evt = new Event("evt"); initialState.TransitionOn(evt).To(state1); substate1.TransitionOn(evt).To(substate2); evt.Fire(); evt.Fire(); parent.Reset(); Assert.IsNull(child.CurrentState); }
public void EventsFiredFromHandlersCallsSynchronizer() { var sm = new StateMachine("sm"); var initial = sm.CreateInitialState("initial"); var state1 = sm.CreateState("state1"); var state2 = sm.CreateState("state2"); var evt = new Event("evt"); initial.TransitionOn(evt).To(state1).WithHandler(i => evt.Fire()); state1.TransitionOn(evt).To(state2); var synchornizer = new Mock<IStateMachineSynchronizer>(); sm.Synchronizer = synchornizer.Object; // Fire the first, capture the second bool calledOnce = false; Func<bool> fireFunc = null; synchornizer.Setup(x => x.FireEvent(It.IsAny<Func<bool>>(), EventFireMethod.Fire)) .Callback<Func<bool>, EventFireMethod>((func, _) => { if (!calledOnce) { // Need to set this before invoking func(), as we'll recurse calledOnce = true; func(); } else { fireFunc = func; } }); evt.Fire(); Assert.AreEqual(state1, sm.CurrentState); Assert.NotNull(fireFunc); fireFunc(); Assert.AreEqual(state2, sm.CurrentState); }
public void CurrentStateReflectsCurrentState() { var sm = new StateMachine("state machine"); var initialState = sm.CreateInitialState("initial state"); var state1 = sm.CreateState("state1"); var evt = new Event("evt"); initialState.TransitionOn(evt).To(state1); Assert.AreEqual(initialState, sm.CurrentState); evt.Fire(); Assert.AreEqual(state1, sm.CurrentState); }
public void EventFireCallsSynchronizerEventFire() { var sm = new StateMachine("sm"); var initial = sm.CreateInitialState("initial"); var evt = new Event("evt"); initial.TransitionOn(evt).To(initial); var synchronizer = new Mock<IStateMachineSynchronizer>(); sm.Synchronizer = synchronizer.Object; evt.Fire(); synchronizer.Verify(x => x.FireEvent(It.IsAny<Func<bool>>(), EventFireMethod.Fire)); }
public void ResetResetsCurrentStateOfStateMachine() { var sm = new StateMachine("sm"); var initial = sm.CreateInitialState("initial"); var state1 = sm.CreateState("state1"); var evt = new Event("evt"); initial.TransitionOn(evt).To(state1); evt.Fire(); sm.Reset(); Assert.AreEqual(initial, sm.CurrentState); }
public void FireThrowsIfTransitionNotFound() { var sm = new StateMachine("sm"); var initialState = sm.CreateInitialState("initialState"); var state1 = sm.CreateState("state1"); var evt = new Event("evt"); state1.TransitionOn(evt).To(initialState); var e = Assert.Throws<TransitionNotFoundException>(() => evt.Fire()); Assert.AreEqual(initialState, e.From); Assert.AreEqual(evt, e.Event); Assert.AreEqual(sm, e.StateMachine); }
public void ResetEmptiesTransitionQueue() { var sm = new StateMachine("parent"); var state1 = sm.CreateInitialState("state1"); var state2 = sm.CreateState("state2"); var evt = new Event("evt"); state1.TransitionOn(evt).To(state2).WithHandler(i => { evt.Fire(); sm.Reset(); }); state2.TransitionOn(evt).To(state1); evt.Fire(); // Make sure that the queued event didn't get fired Assert.AreEqual(state2, sm.CurrentState); // Make sure nothing's been queued evt.Fire(); Assert.AreEqual(state1, sm.CurrentState); }
public void IgnoredEventsDontTakePriorityOverNormalTransitions() { var sm = new StateMachine("sm"); var state1 = sm.CreateInitialState("state1"); var state2 = sm.CreateState("state2"); var evt = new Event("evt"); var evt2 = new Event("evt2"); state1.TransitionOn(evt).To(state2).WithGuard(i => true); state1.Ignore(evt, evt2); evt.Fire(); Assert.True(state2.IsCurrent); }
public void IgnoredTEventDontTriggerTransitionNotFoundEvents() { var sm = new StateMachine("sm"); var state1 = sm.CreateInitialState("state1"); var evt = new Event<string>("evt"); state1.Ignore(evt); bool called = false; sm.TransitionNotFound += (o, e) => called = true; evt.Fire("foo"); Assert.False(called); }
public void FirstRegisteredTransitionWins() { var sm = new StateMachine("state machine"); var initial = sm.CreateInitialState("initial"); var state1 = sm.CreateState("state1"); var state2 = sm.CreateState("state2"); var evt = new Event("evt"); initial.TransitionOn(evt).To(state2).WithGuard(i => true); initial.TransitionOn(evt).To(state1); evt.Fire(); Assert.AreEqual(state2, sm.CurrentState); }
public void CorrectHandlersAreInvokedInNormalTransition() { var events = new List<string>(); var sm = new StateMachine("State Machine"); var evt = new Event("Event"); var state1 = sm.CreateInitialState("State 1") .WithEntry(i => events.Add("State 1 Entry")) .WithExit(i => events.Add("State 1 Exit")); var state2 = sm.CreateState("State 2") .WithEntry(i => events.Add("State 2 Entry")) .WithExit(i => events.Add("State 2 Exit")); var transition = state1.TransitionOn(evt).To(state2).WithHandler(i => events.Add("Transition 1 2")); evt.Fire(); Assert.That(events, Is.EquivalentTo(new[] { "State 1 Exit", "Transition 1 2", "State 2 Entry" })); }
public void StateMachineReportsCurrentStateCorrectly() { var stateMachine = new StateMachine("State Machine"); var state1 = stateMachine.CreateInitialState("State 1"); var state2 = stateMachine.CreateState("State 2"); var evt = new Event("Event"); var subSm = state2.CreateChildStateMachine(); var state21 = subSm.CreateInitialState("State 2.1"); state1.TransitionOn(evt).To(state2); evt.Fire(); Assert.AreEqual(state2, stateMachine.CurrentState); Assert.AreEqual(state2, ((IStateMachine)stateMachine).CurrentState); Assert.AreEqual(state21, subSm.CurrentState); Assert.AreEqual(state21, ((IStateMachine)subSm).CurrentState); }
public void DoesNotFireHandlersWhenTransitioningBetweenTwoStatesInGroup() { var sm = new StateMachine("State Machine"); var state1 = sm.CreateInitialState("State 1"); var state2 = sm.CreateState("State 2"); var evt = new Event("Event"); bool fired = false; var group = new StateGroup<State>("Group") .WithEntry(i => fired = true) .WithExit(i => fired = true); state1.AddToGroup(group); state2.AddToGroup(group); state1.TransitionOn(evt).To(state2); evt.Fire(); Assert.False(fired); }
public void CorrectInfoIsGivenInExitHandler() { StateHandlerInfo<State> handlerInfo = null; var sm = new StateMachine("State Machine"); var evt = new Event("Event"); var state1 = sm.CreateInitialState("State 1").WithExit(i => handlerInfo = i); var state2 = sm.CreateState("State 2"); state1.TransitionOn(evt).To(state2); evt.Fire(); Assert.NotNull(handlerInfo); Assert.AreEqual(state1, handlerInfo.From); Assert.AreEqual(state2, handlerInfo.To); Assert.AreEqual(evt, handlerInfo.Event); Assert.Null(handlerInfo.EventData); }
public void IgnoredEventsDoTriggerEventIgnoredEvents() { var sm = new StateMachine("sm"); var state1 = sm.CreateInitialState("state1"); var evt = new Event<string>("evt"); var evt2 = new Event<string>("evt2"); state1.Ignore(evt, evt2); EventIgnoredEventArgs<State> ea = null; sm.EventIgnored += (o, e) => ea = e; evt.Fire("foo"); Assert.NotNull(ea); Assert.AreEqual(evt, ea.Event); Assert.AreEqual(state1, ea.State); Assert.AreEqual(EventFireMethod.Fire, ea.EventFireMethod); }
public void StateMachineReportsIsActiveCorrectly() { var parent = new StateMachine(); var state1 = parent.CreateInitialState("state1"); var state2 = parent.CreateState("state2"); var state2Child = state2.CreateChildStateMachine("childSm"); var state21 = state2Child.CreateInitialState("state21"); var evt = new Event("evt"); state1.TransitionOn(evt).To(state2); Assert.True(parent.IsActive); Assert.False(state2Child.IsActive); evt.Fire(); Assert.True(parent.IsActive); Assert.True(state2Child.IsActive); }
public void EventInEntryHandlerPropagatedCorrectly() { var sm = new StateMachine("State Machine"); var state1 = sm.CreateInitialState("State 1"); var state2 = sm.CreateState("State 2"); var evt = new Event("Event"); state1.TransitionOn(evt).To(state2); var ex = new Exception("Foo"); var group = new StateGroup<State>("Group") .WithEntry(i => { throw ex; }); state2.AddToGroup(group); var e = Assert.Throws<TransitionFailedException>(() => evt.Fire()); Assert.AreEqual(state1, e.FaultInfo.From); Assert.AreEqual(state2, e.FaultInfo.To); Assert.AreEqual(evt, e.FaultInfo.Event); Assert.AreEqual(ex, e.FaultInfo.Exception); Assert.AreEqual(sm, e.FaultInfo.StateMachine); Assert.AreEqual(FaultedComponent.GroupEntryHandler, e.FaultInfo.FaultedComponent); Assert.AreEqual(group, e.FaultInfo.Group); }
public void TransitionRaisedWhenInnerSelfTransitionOnChild() { var sm = new StateMachine("sm"); var initial = sm.CreateInitialState("initial"); var child = initial.CreateChildStateMachine(); var childInitial = child.CreateInitialState("childInitial"); var evt = new Event("evt"); childInitial.InnerSelfTransitionOn(evt); TransitionEventArgs<State> ea = null; sm.Transition += (o, e) => { ea = e; }; evt.Fire(); Assert.NotNull(ea); Assert.AreEqual(childInitial, ea.From); Assert.AreEqual(childInitial, ea.To); Assert.AreEqual(evt, ea.Event); Assert.True(ea.IsInnerTransition); Assert.AreEqual(EventFireMethod.Fire, ea.EventFireMethod); }
public void FuncThrowsExceptionIfEventFireFailed() { var sm = new StateMachine("sm"); var initial = sm.CreateInitialState("initial"); var state1 = sm.CreateState("state 1"); var evt = new Event("evt"); state1.InnerSelfTransitionOn(evt); var synchronizer = new Mock<IStateMachineSynchronizer>(); Func<bool> fireFunc = null; synchronizer.Setup(x => x.FireEvent(It.IsAny<Func<bool>>(), EventFireMethod.Fire)) .Callback<Func<bool>, EventFireMethod>((func, _) => fireFunc = func); sm.Synchronizer = synchronizer.Object; evt.Fire(); Assert.Throws<TransitionNotFoundException>(() => fireFunc()); }
public void IndicatesWhetherInState() { var sm = new StateMachine("State Machine"); var state1 = sm.CreateInitialState("State 1"); var state2 = sm.CreateState("State 2"); var state3 = sm.CreateState("State 3"); var evt = new Event("Event"); var group1 = new StateGroup<State>("Group 1"); var group2 = new StateGroup<State>("Group 2"); state1.AddToGroup(group1); state2.AddToGroup(group2); state3.AddToGroup(group2); state1.TransitionOn(evt).To(state2); state2.TransitionOn(evt).To(state3); Assert.True(group1.IsCurrent); Assert.False(group2.IsCurrent); evt.Fire(); Assert.False(group1.IsCurrent); Assert.True(group2.IsCurrent); evt.Fire(); Assert.False(group1.IsCurrent); Assert.True(group2.IsCurrent); }
public void IsCurrentIncludesChildStateMachines() { var sm = new StateMachine("State Machine"); var state1 = sm.CreateInitialState("State 1"); var subSm = state1.CreateChildStateMachine(); var state11 = subSm.CreateInitialState("State 1.1"); var state12 = subSm.CreateState("State 1.2"); var group = new StateGroup<State>("Group"); state1.AddToGroup(group); var evt = new Event("Event"); state11.TransitionOn(evt).To(state12); Assert.True(group.IsCurrent); evt.Fire(); Assert.True(group.IsCurrent); }
public void FiresExitHandlerWithCorrectArgumentsWhenExited() { var sm = new StateMachine("State Machine"); var state1 = sm.CreateInitialState("State 1"); var state2 = sm.CreateState("State 2"); var evt = new Event("Event"); StateHandlerInfo<State> info = null; var group = new StateGroup<State>("Group") .WithExit(i => info = i); state1.AddToGroup(group); state1.TransitionOn(evt).To(state2); evt.Fire(); Assert.NotNull(info); Assert.AreEqual(state1, info.From); Assert.AreEqual(state2, info.To); Assert.AreEqual(evt, info.Event); }
public void FalseReturnValueDoesNotCauseExceptionToBeThrownByFire() { var sm = new StateMachine("sm"); var initial = sm.CreateInitialState("initial"); var state1 = sm.CreateState("State 1"); var evt = new Event("evt"); state1.InnerSelfTransitionOn(evt); var synchronizer = new Mock<IStateMachineSynchronizer>(); synchronizer.Setup(x => x.FireEvent(It.IsAny<Func<bool>>(), EventFireMethod.TryFire)) .Returns(false); sm.Synchronizer = synchronizer.Object; Assert.DoesNotThrow(() => evt.Fire()); }
public void StateMachineDoesNotFireEventUntilFuncIsInvoked() { var sm = new StateMachine("sm"); var initial = sm.CreateInitialState("initial"); var state1 = sm.CreateState("state1"); var evt = new Event("evt"); initial.TransitionOn(evt).To(state1); var synchronizer = new Mock<IStateMachineSynchronizer>(); Func<bool> fireFunc = null; synchronizer.Setup(x => x.FireEvent(It.IsAny<Func<bool>>(), EventFireMethod.Fire)) .Callback<Func<bool>, EventFireMethod>((func, _) => fireFunc = func); sm.Synchronizer = synchronizer.Object; evt.Fire(); Assert.AreEqual(initial, sm.CurrentState); Assert.NotNull(fireFunc); Assert.True(fireFunc()); Assert.AreEqual(state1, sm.CurrentState); }
public void StateMachineDoesNotResetUntilActionIsInvoked() { // Need to transition, so we can tell when it's reset var sm = new StateMachine("sm"); var initial = sm.CreateInitialState("initial"); var state1 = sm.CreateState("state1"); var evt = new Event("evt"); initial.TransitionOn(evt).To(state1); evt.Fire(); var synchronizer = new Mock<IStateMachineSynchronizer>(); sm.Synchronizer = synchronizer.Object; Action resetAction = null; synchronizer.Setup(x => x.Reset(It.IsAny<Action>())).Callback((Action action) => resetAction = action); sm.Reset(); Assert.AreEqual(state1, sm.CurrentState); Assert.NotNull(resetAction); resetAction(); Assert.AreEqual(initial, sm.CurrentState); }
public void ExceptionFromFireEventIsPropagatedBackToEventFire() { var sm = new StateMachine("sm"); var initial = sm.CreateInitialState("initial"); var state2 = sm.CreateState("State 2"); var evt = new Event("evt"); state2.TransitionOn(evt).To(state2); var exception = new Exception("foo"); var synchronizer = new Mock<IStateMachineSynchronizer>(); synchronizer.Setup(x => x.FireEvent(It.IsAny<Func<bool>>(), EventFireMethod.Fire)) .Callback(() => { throw exception; }); sm.Synchronizer = synchronizer.Object; var e = Assert.Throws<Exception>(() => evt.Fire()); Assert.AreEqual(exception, e); }