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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
        }
예제 #4
0
        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();
        }
예제 #5
0
        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));
        }
예제 #9
0
        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);
        }
예제 #10
0
        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);
        }
예제 #11
0
        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);
        }
예제 #14
0
        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);
        }
예제 #15
0
        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" }));
        }
예제 #16
0
        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);
        }
예제 #17
0
        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);
        }
예제 #18
0
        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);
        }
예제 #20
0
        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);
        }
예제 #21
0
        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());
        }
예제 #24
0
        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);
        }
예제 #25
0
        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);
        }
예제 #26
0
        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);
        }