Skip to content

Commit

Permalink
Create some tests for state groups, and tweak slightly
Browse files Browse the repository at this point in the history
  • Loading branch information
canton7 committed Aug 25, 2015
1 parent 7043604 commit b7b82a9
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 12 deletions.
4 changes: 2 additions & 2 deletions src/StateMechanic/StateGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public class StateGroup : IStateGroup<State>
{
private readonly StateGroupInner<State> innerStateGroup;

internal StateGroup(string name)
public StateGroup(string name)
{
this.innerStateGroup = new StateGroupInner<State>(name);
}
Expand Down Expand Up @@ -137,7 +137,7 @@ public class StateGroup<TStateData> : IStateGroup<State<TStateData>>
{
private readonly StateGroupInner<State<TStateData>> innerStateGroup;

internal StateGroup(string name)
public StateGroup(string name)
{
this.innerStateGroup = new StateGroupInner<State<TStateData>>(name);
}
Expand Down
21 changes: 11 additions & 10 deletions src/StateMechanic/StateMachineKernel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;

namespace StateMechanic
{
Expand All @@ -24,7 +25,7 @@ public void CoordinateTransition(TState from, TState to, IEvent @event, bool isI
if (from.ChildStateMachine != null)
this.ExitChildStateMachine(from.ChildStateMachine, to, @event);

this.ExitState(from, stateHandlerInfo);
this.ExitState(stateHandlerInfo);
}

if (handlerInvoker != null)
Expand All @@ -43,7 +44,7 @@ public void CoordinateTransition(TState from, TState to, IEvent @event, bool isI

if (!isInnerTransition)
{
this.EnterState(to, stateHandlerInfo);
this.EnterState(stateHandlerInfo);

if (to.ChildStateMachine != null)
this.EnterChildStateMachine(to.ChildStateMachine, from, @event);
Expand All @@ -59,7 +60,7 @@ private void ExitChildStateMachine(IStateMachine<TState> childStateMachine, TSta
this.ExitChildStateMachine(childStateMachine.CurrentState.ChildStateMachine, to, @event);
}

this.ExitState(childStateMachine.CurrentState, new StateHandlerInfo<TState>(childStateMachine.CurrentState, to, @event));
this.ExitState(new StateHandlerInfo<TState>(childStateMachine.CurrentState, to, @event));

childStateMachine.SetCurrentState(null);
}
Expand All @@ -68,26 +69,26 @@ private void EnterChildStateMachine(IStateMachine<TState> childStateMachine, TSt
{
childStateMachine.SetCurrentState(childStateMachine.InitialState);

this.EnterState(childStateMachine.InitialState, new StateHandlerInfo<TState>(from, childStateMachine.InitialState, @event));
this.EnterState(new StateHandlerInfo<TState>(from, childStateMachine.InitialState, @event));

if (childStateMachine.InitialState.ChildStateMachine != null)
{
this.EnterChildStateMachine(childStateMachine.InitialState.ChildStateMachine, from, @event);
}
}

private void ExitState(TState state, StateHandlerInfo<TState> info)
private void ExitState(StateHandlerInfo<TState> info)
{
try
{
state.FireExitHandler(info);
info.From.FireExitHandler(info);
}
catch (Exception e)
{
throw new InternalTransitionFaultException(info.From, info.To, info.Event, FaultedComponent.ExitHandler, e);
}

foreach (var group in state.Groups)
foreach (var group in info.From.Groups.Reverse().Except(info.To.Groups))
{
try
{
Expand All @@ -100,18 +101,18 @@ private void ExitState(TState state, StateHandlerInfo<TState> info)
}
}

private void EnterState(TState state, StateHandlerInfo<TState> info)
private void EnterState(StateHandlerInfo<TState> info)
{
try
{
state.FireEntryHandler(info);
info.To.FireEntryHandler(info);
}
catch (Exception e)
{
throw new InternalTransitionFaultException(info.From, info.To, info.Event, FaultedComponent.EntryHandler, e);
}

foreach (var group in state.Groups)
foreach (var group in info.To.Groups.Except(info.From.Groups))
{
try
{
Expand Down
205 changes: 205 additions & 0 deletions src/StateMechanicUnitTests/StateGroupTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NUnit.Framework;
using StateMechanic;

namespace StateMechanicUnitTests
{
[TestFixture]
public class StateGroupTests
{
[Test]
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 = sm.CreateEvent("Event");
var group1 = new StateGroup("Group 1");
var group2 = new StateGroup("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);
}

[Test]
public void IsCurrentIncludesChildStateMachines()
{
var sm = new StateMachine("State Machine");
var state1 = sm.CreateInitialState("State 1");
var subSm = state1.CreateChildStateMachine("Child State Machine");
var state11 = subSm.CreateInitialState("State 1.1");
var state12 = subSm.CreateState("State 1.2");

var group = new StateGroup("Group");
state1.AddToGroup(group);

var evt = sm.CreateEvent("Event");
state11.TransitionOn(evt).To(state12);

Assert.True(group.IsCurrent);

evt.Fire();

Assert.True(group.IsCurrent);
}

[Test]
public void FiresEntryHandlerWithCorrectArgumentsWhenEntered()
{
var sm = new StateMachine("State Machine");
var state1 = sm.CreateInitialState("State 1");
var state2 = sm.CreateState("State 2");
var evt = sm.CreateEvent("Event");
StateHandlerInfo<State> info = null;
var group = new StateGroup("Group")
.WithEntry(i => info = i);
state2.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);
}

[Test]
public void FiresExitHandlerWithCorrectArgumentsWhenExited()
{
var sm = new StateMachine("State Machine");
var state1 = sm.CreateInitialState("State 1");
var state2 = sm.CreateState("State 2");
var evt = sm.CreateEvent("Event");
StateHandlerInfo<State> info = null;
var group = new StateGroup("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);
}

[Test]
public void DoesNotFireHandlersWhenTransitioningBetweenTwoStatesInGroup()
{
var sm = new StateMachine("State Machine");
var state1 = sm.CreateInitialState("State 1");
var state2 = sm.CreateState("State 2");
var evt = sm.CreateEvent("Event");
bool fired = false;
var group = new StateGroup("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);
}

[Test]
public void StateGroupListsStatesCorerctly()
{
var sm = new StateMachine("State Machine");
var state1 = sm.CreateInitialState("State 1");
var state2 = sm.CreateState("State 2");
var group = new StateGroup("Group");
state1.AddToGroup(group);
state2.AddToGroup(group);

Assert.That(group.States, Is.EqualTo(new[] { state1, state2 }));
}

[Test]
public void StateListsStateGroupsCorrectly()
{
var sm = new StateMachine("State Machine");
var state1 = sm.CreateInitialState("State 1");
var group1 = new StateGroup("Group 1");
var group2 = new StateGroup("Group 2");
state1.AddToGroup(group1);
state1.AddToGroup(group2);

Assert.That(state1.Groups, Is.EquivalentTo(new[] { group1, group2 }));
}

[Test]
public void EventInEntryHandlerPropagatedCorrectly()
{
var sm = new StateMachine("State Machine");
var state1 = sm.CreateInitialState("State 1");
var state2 = sm.CreateState("State 2");
var evt = sm.CreateEvent("Event");
state1.TransitionOn(evt).To(state2);

var ex = new Exception("Foo");
var group = new StateGroup("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);
}

[Test]
public void EventInExitHandlerPropagatedCorrectly()
{
var sm = new StateMachine("State Machine");
var state1 = sm.CreateInitialState("State 1");
var state2 = sm.CreateState("State 2");
var evt = sm.CreateEvent("Event");
state1.TransitionOn(evt).To(state2);

var ex = new Exception("Foo");
var group = new StateGroup("Group")
.WithExit(i => { throw ex; });
state1.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.GroupExitHandler, e.FaultInfo.FaultedComponent);
Assert.AreEqual(group, e.FaultInfo.Group);
}
}
}
1 change: 1 addition & 0 deletions src/StateMechanicUnitTests/StateMechanicUnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
<Compile Include="IntrospectionTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ResetTests.cs" />
<Compile Include="StateGroupTests.cs" />
<Compile Include="StateMachineStateTests.cs" />
<Compile Include="StateMachineSynchronizerTests.cs" />
<Compile Include="TransitionNotificationTests.cs" />
Expand Down

0 comments on commit b7b82a9

Please sign in to comment.