Skip to content

Commit

Permalink
Merge pull request #590 from mclift/bugfix/reentry-transition-missing…
Browse files Browse the repository at this point in the history
…-function-in-dotgraph

Show state entry function in re-entry transition in dot graph
  • Loading branch information
mclift authored Jul 22, 2024
2 parents c896d66 + 6b2cb9f commit 7223486
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 8 deletions.
10 changes: 2 additions & 8 deletions src/Stateless/Graph/GraphStyleBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,11 @@ public virtual List<string> FormatAllTransitions(List<Transition> transitions)
line = FormatOneTransition(stay.SourceState.NodeName, stay.Trigger.UnderlyingTrigger.ToString(),
null, stay.SourceState.NodeName, stay.Guards.Select(x => x.Description));
}
else if (stay.SourceState.EntryActions.Count == 0)
{
line = FormatOneTransition(stay.SourceState.NodeName, stay.Trigger.UnderlyingTrigger.ToString(),
null, stay.SourceState.NodeName, stay.Guards.Select(x => x.Description));
}
else
{
// There are entry functions into the state, so call out that this transition
// does invoke them (since normally a transition back into the same state doesn't)
line = FormatOneTransition(stay.SourceState.NodeName, stay.Trigger.UnderlyingTrigger.ToString(),
stay.SourceState.EntryActions, stay.SourceState.NodeName, stay.Guards.Select(x => x.Description));
stay.DestinationEntryActions.Select(x => x.Method.Description),
stay.SourceState.NodeName, stay.Guards.Select(x => x.Description));
}
}
else
Expand Down
10 changes: 10 additions & 0 deletions src/Stateless/Graph/StateGraph.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@ void AddTransitions(StateMachineInfo machineInfo)
Transitions.Add(stay);
fromState.Leaving.Add(stay);
fromState.Arriving.Add(stay);

// If the reentrant transition causes the state's entry action to be executed, this is shown
// explicity in the state graph by adding it to the DestinationEntryActions list.
if (stay.ExecuteEntryExitActions)
{
foreach (var action in stateInfo.EntryActions.Where(a => a.FromTrigger is null))
{
stay.DestinationEntryActions.Add(action);
}
}
}
else
{
Expand Down
59 changes: 59 additions & 0 deletions test/Stateless.Tests/DotGraphFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,65 @@ public void Initial_State_Not_Changed_After_Trigger_Fired()
Assert.Equal(expected, dotGraph);
}

[Fact]
public void Reentrant_Transition_Shows_Entry_Action_When_Action_Is_Configured_With_OnEntryFrom()
{
var expected = Prefix(Style.UML)
+ Box(Style.UML, "A")
+ Box(Style.UML, "B")
+ Line("A", "B", "X / OnEntry")
+ Line("B", "B", "X / OnEntry")
+ suffix;

var sm = new StateMachine<State, Trigger>(State.A);

sm.Configure(State.A)
.Permit(Trigger.X, State.B);

var list = new List<string>();
sm.Configure(State.B)
.OnEntryFrom(Trigger.X, OnEntry, entryActionDescription: "OnEntry")
.PermitReentry(Trigger.X);

string dotGraph = UmlDotGraph.Format(sm.GetInfo());

#if WRITE_DOTS_TO_FOLDER
System.IO.File.WriteAllText(DestinationFolder + "Reentrant_Transition_Shows_Entry_Action_When_Action_Is_Configured_With_OnEntryFrom.dot", dotGraph);
#endif

Assert.Equal(expected, dotGraph);
}

[Fact]
public void Reentrant_Transition_Shows_Entry_Action_When_Action_Is_Configured_With_OnEntryFrom_And_Trigger_Has_Parameter()
{
var expected = Prefix(Style.UML)
+ Box(Style.UML, "A")
+ Box(Style.UML, "B")
+ Line("A", "B", "X / LogTrigger")
+ Line("B", "B", "X / LogTrigger")
+ suffix;

var sm = new StateMachine<State, Trigger>(State.A);
var triggerX = sm.SetTriggerParameters<string>(Trigger.X);

sm.Configure(State.A)
.Permit(Trigger.X, State.B);

var list = new List<string>();
sm.Configure(State.B)
.OnEntryFrom(triggerX, list.Add, entryActionDescription: "LogTrigger")
.PermitReentry(Trigger.X);

string dotGraph = UmlDotGraph.Format(sm.GetInfo());

#if WRITE_DOTS_TO_FOLDER
System.IO.File.WriteAllText(DestinationFolder + "Reentrant_Transition_Shows_Entry_Action_When_Action_Is_Configured_With_OnEntryFrom_And_Trigger_Has_Parameter.dot", dotGraph);
#endif

Assert.Equal(expected, dotGraph);
}

private void TestEntryAction() { }
private void TestEntryActionString(string val) { }
private State DestinationSelector() { return State.A; }
Expand Down

0 comments on commit 7223486

Please sign in to comment.