Skip to content

Commit

Permalink
Merge pull request dotnet-state-machine#82 from HenningNT/master
Browse files Browse the repository at this point in the history
Adding InternalAction with similar signature to OnEntryFrom
  • Loading branch information
nblumhardt authored Oct 3, 2016
2 parents 4b641bb + de199f3 commit 9a48bd2
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 16 deletions.
85 changes: 81 additions & 4 deletions Stateless.Tests/InternalTransitionFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class InternalTransitionFixture
/// This will fail if the state changes after the trigger has fired.
/// </summary>
[Test]
public void StayInSameStateOneState()
public void StayInSameStateOneState_Transition()
{
var sm = new StateMachine<State, Trigger>(State.A);
sm.Configure(State.A)
Expand All @@ -23,7 +23,7 @@ public void StayInSameStateOneState()
}

[Test]
public void StayInSameStateTwoStates()
public void StayInSameStateTwoStates_Transition()
{
var sm = new StateMachine<State, Trigger>(State.A);

Expand All @@ -49,7 +49,7 @@ public void StayInSameStateTwoStates()
Assert.AreEqual(State.B, sm.State);
}
[Test]
public void StayInSameSubStateTransitionInSupersate()
public void StayInSameSubStateTransitionInSuperstate_Transition()
{
var sm = new StateMachine<State, Trigger>(State.B);

Expand All @@ -65,7 +65,7 @@ public void StayInSameSubStateTransitionInSupersate()
Assert.AreEqual(State.B, sm.State);
}
[Test]
public void StayInSameSubStateTransitionInSubstate()
public void StayInSameSubStateTransitionInSubstate_Transition()
{
var sm = new StateMachine<State, Trigger>(State.B);

Expand All @@ -80,5 +80,82 @@ public void StayInSameSubStateTransitionInSubstate()
sm.Fire(Trigger.X);
Assert.AreEqual(State.B, sm.State);
}

[Test]
public void StayInSameStateOneState_Action()
{
var sm = new StateMachine<State, Trigger>(State.A);
sm.Configure(State.A)
.InternalTransition(Trigger.X, () => { });

Assert.AreEqual(State.A, sm.State);
sm.Fire(Trigger.X);
Assert.AreEqual(State.A, sm.State);
}

[Test]
public void StayInSameStateTwoStates_Action()
{
var sm = new StateMachine<State, Trigger>(State.A);

sm.Configure(State.A)
.InternalTransition(Trigger.X, () => { })
.Permit(Trigger.Y, State.B);

sm.Configure(State.B)
.InternalTransition(Trigger.X, () => { })
.Permit(Trigger.Y, State.A);

// This should not cause any state changes
Assert.AreEqual(State.A, sm.State);
sm.Fire(Trigger.X);
Assert.AreEqual(State.A, sm.State);

// Change state to B
sm.Fire(Trigger.Y);

// This should also not cause any state changes
Assert.AreEqual(State.B, sm.State);
sm.Fire(Trigger.X);
Assert.AreEqual(State.B, sm.State);
}
[Test]
public void StayInSameSubStateTransitionInSuperstate_Action()
{
var sm = new StateMachine<State, Trigger>(State.B);

sm.Configure(State.A)
.InternalTransition(Trigger.X, () => { })
.InternalTransition(Trigger.Y, () => { });

sm.Configure(State.B)
.SubstateOf(State.A);

// This should not cause any state changes
Assert.AreEqual(State.B, sm.State);
sm.Fire(Trigger.X);
Assert.AreEqual(State.B, sm.State);
sm.Fire(Trigger.Y);
Assert.AreEqual(State.B, sm.State);
}
[Test]
public void StayInSameSubStateTransitionInSubstate_Action()
{
var sm = new StateMachine<State, Trigger>(State.B);

sm.Configure(State.A);

sm.Configure(State.B)
.SubstateOf(State.A)
.InternalTransition(Trigger.X, () => { })
.InternalTransition(Trigger.Y, () => { });

// This should not cause any state changes
Assert.AreEqual(State.B, sm.State);
sm.Fire(Trigger.X);
Assert.AreEqual(State.B, sm.State);
sm.Fire(Trigger.Y);
Assert.AreEqual(State.B, sm.State);
}
}
}
43 changes: 31 additions & 12 deletions Stateless/StateConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,41 +48,61 @@ public StateConfiguration Permit(TTrigger trigger, TState destinationState)
return InternalPermit(trigger, destinationState, string.Empty);
}
/// <summary>
///
/// Add an internal transition to the state machine. An internal action does not cause the Exit and Entry actions to be triggered, and does not change the state of the state machine
/// </summary>
/// <param name="trigger"></param>
/// <param name="entryAction"></param>
/// <returns></returns>
public StateConfiguration InternalTransition(TTrigger trigger, Action<Transition> entryAction)
{
if (entryAction == null) throw new ArgumentNullException(nameof(entryAction));

_representation.AddTriggerBehaviour(new InternalTriggerBehaviour(trigger));
_representation.AddInternalAction(trigger, (t, args) => entryAction(t));
return this;
}
/// <summary>
///
/// Add an internal transition to the state machine. An internal action does not cause the Exit and Entry actions to be triggered, and does not change the state of the state machine
/// </summary>
/// <param name="trigger">The accepted trigger</param>
/// <param name="internalAction">The action performed by the internal transition</param>
/// <returns></returns>
public StateConfiguration InternalTransition(TTrigger trigger, Action internalAction)
{
if (internalAction == null) throw new ArgumentNullException(nameof(internalAction));

_representation.AddTriggerBehaviour(new InternalTriggerBehaviour(trigger));
_representation.AddInternalAction(trigger, (t, args) => internalAction());
return this;
}
/// <summary>
/// Add an internal transition to the state machine. An internal action does not cause the Exit and Entry actions to be triggered, and does not change the state of the state machine
/// </summary>
/// <typeparam name="TArg0"></typeparam>
/// <param name="trigger"></param>
/// <param name="entryAction"></param>
/// <param name="trigger">The accepted trigger</param>
/// <param name="internalAction">The action performed by the internal transition</param>
/// <returns></returns>
public StateConfiguration InternalTransition<TArg0>(TTrigger trigger, Action<Transition> entryAction)
public StateConfiguration InternalTransition<TArg0>(TTrigger trigger, Action<Transition> internalAction)
{
if (internalAction == null) throw new ArgumentNullException(nameof(internalAction));

_representation.AddTriggerBehaviour(new InternalTriggerBehaviour(trigger));
_representation.AddInternalAction(trigger, (t, args) => entryAction(t));
_representation.AddInternalAction(trigger, (t, args) => internalAction(t));
return this;
}
/// <summary>
///
/// Add an internal transition to the state machine. An internal action does not cause the Exit and Entry actions to be triggered, and does not change the state of the state machine
/// </summary>
/// <typeparam name="TArg0"></typeparam>
/// <param name="trigger"></param>
/// <param name="entryAction"></param>
/// <param name="trigger">The accepted trigger</param>
/// <param name="internalAction">The action performed by the internal transition</param>
/// <returns></returns>
public StateConfiguration InternalTransition<TArg0>(TriggerWithParameters<TArg0> trigger, Action<TArg0, Transition> entryAction)
public StateConfiguration InternalTransition<TArg0>(TriggerWithParameters<TArg0> trigger, Action<TArg0, Transition> internalAction)
{
if (internalAction == null) throw new ArgumentNullException(nameof(internalAction));

_representation.AddTriggerBehaviour(new InternalTriggerBehaviour(trigger.Trigger));
_representation.AddInternalAction(trigger.Trigger, (t, args) => entryAction(ParameterConversion.Unpack<TArg0>(args, 0), t));
_representation.AddInternalAction(trigger.Trigger, (t, args) => internalAction(ParameterConversion.Unpack<TArg0>(args, 0), t));
return this;
}
/// <summary>
Expand All @@ -104,7 +124,6 @@ public StateConfiguration PermitIf(TTrigger trigger, TState destinationState, Fu
guard,
guardDescription ?? guard?.TryGetMethodInfo().Name);
}

/// <summary>
/// Accept the specified trigger, execute exit actions and re-execute entry actions.
/// Reentry behaves as though the configured state transitions to an identical sibling state.
Expand Down

0 comments on commit 9a48bd2

Please sign in to comment.