Skip to content

Commit

Permalink
Fixed #83 - wasn't assigning superState property
Browse files Browse the repository at this point in the history
  • Loading branch information
phatboyg committed Feb 6, 2022
1 parent 5abf2ad commit b50e86f
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 20 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: Automatonymous
env:
AUTOMATONYMOUS_VERSION: 5.1.3
AUTOMATONYMOUS_VERSION: 5.1.4
DOTNET_CLI_TELEMETRY_OPTOUT: 1
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT: true
on:
Expand Down
36 changes: 17 additions & 19 deletions src/Automatonymous/States/StateMachineState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@ public class StateMachineState<TInstance> :
readonly Dictionary<Event, ActivityBehaviorBuilder<TInstance>> _behaviors;
readonly Dictionary<Event, StateEventFilter<TInstance>> _ignoredEvents;
readonly AutomatonymousStateMachine<TInstance> _machine;
readonly string _name;
readonly EventObserver<TInstance> _observer;
readonly HashSet<State<TInstance>> _subStates;
State<TInstance> _superState;

public StateMachineState(AutomatonymousStateMachine<TInstance> machine, string name,
EventObserver<TInstance> observer, State<TInstance> superState = null)
{
_machine = machine;
_name = name;
Name = name;
_observer = observer;

_behaviors = new Dictionary<Event, ActivityBehaviorBuilder<TInstance>>();
Expand All @@ -45,17 +43,17 @@ public StateMachineState(AutomatonymousStateMachine<TInstance> machine, string n

_subStates = new HashSet<State<TInstance>>();

_superState = superState;
SuperState = superState;
superState?.AddSubstate(this);
}

public bool Equals(State other)
{
return string.CompareOrdinal(_name, other?.Name ?? "") == 0;
return string.CompareOrdinal(Name, other?.Name ?? "") == 0;
}

public State<TInstance> SuperState { get; }
public string Name => _name;
public string Name { get; }
public Event Enter { get; }
public Event Leave { get; }
public Event<State> BeforeEnter { get; }
Expand All @@ -76,7 +74,7 @@ public void Accept(StateMachineVisitor visitor)
public void Probe(ProbeContext context)
{
var scope = context.CreateScope("state");
scope.Add("name", _name);
scope.Add("name", Name);

if (_subStates.Any())
{
Expand Down Expand Up @@ -107,10 +105,10 @@ async Task State<TInstance>.Raise(EventContext<TInstance> context)
if (_ignoredEvents.TryGetValue(context.Event, out var filter) && filter.Filter(context))
return;

if (_superState != null)
if (SuperState != null)
try
{
await _superState.Raise(context).ConfigureAwait(false);
await SuperState.Raise(context).ConfigureAwait(false);
return;
}
catch (UnhandledEventException)
Expand Down Expand Up @@ -145,10 +143,10 @@ async Task State<TInstance>.Raise<T>(EventContext<TInstance, T> context)
if (_ignoredEvents.TryGetValue(context.Event, out var filter) && filter.Filter(context))
return;

if (_superState != null)
if (SuperState != null)
try
{
await _superState.Raise(context).ConfigureAwait(false);
await SuperState.Raise(context).ConfigureAwait(false);
return;
}
catch (UnhandledEventException)
Expand Down Expand Up @@ -201,36 +199,36 @@ public void AddSubstate(State<TInstance> subState)
if (subState == null)
throw new ArgumentNullException(nameof(subState));

if (_name.Equals(subState.Name))
if (Name.Equals(subState.Name))
throw new ArgumentException("A state cannot be a substate of itself", nameof(subState));

_subStates.Add(subState);
}

public bool HasState(State<TInstance> state)
{
return _name.Equals(state.Name) || _subStates.Any(s => s.HasState(state));
return Name.Equals(state.Name) || _subStates.Any(s => s.HasState(state));
}

public bool IsStateOf(State<TInstance> state)
{
return _name.Equals(state.Name) || _superState != null && _superState.IsStateOf(state);
return Name.Equals(state.Name) || SuperState != null && SuperState.IsStateOf(state);
}

public IEnumerable<Event> Events
{
get
{
if (_superState != null)
return _superState.Events.Union(GetStateEvents()).Distinct();
if (SuperState != null)
return SuperState.Events.Union(GetStateEvents()).Distinct();

return GetStateEvents();
}
}

public int CompareTo(State other)
{
return string.CompareOrdinal(_name, other.Name);
return string.CompareOrdinal(Name, other.Name);
}

bool IsRealEvent(Event @event)
Expand Down Expand Up @@ -261,7 +259,7 @@ public override bool Equals(object obj)

public override int GetHashCode()
{
return _name?.GetHashCode() ?? 0;
return Name?.GetHashCode() ?? 0;
}

public static bool operator ==(State<TInstance> left, StateMachineState<TInstance> right)
Expand Down Expand Up @@ -296,7 +294,7 @@ public override int GetHashCode()

public override string ToString()
{
return $"{_name} (State)";
return $"{Name} (State)";
}
}
}
78 changes: 78 additions & 0 deletions tests/Automatonymous.Tests/SubState_Specs.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
namespace Automatonymous.Tests
{
using System;
using System.Threading.Tasks;
using NUnit.Framework;


[TestFixture]
public class SubStateOnEnter_Specs
{
[Test]
public async Task Should_raise_both_enter_events()
{
var instance = new StateData();
var machine = new StateMachine();
var observer = new StateChangeObserver<StateData>();
var eventObserver = new EventRaisedObserver<StateData>();

using var subscription = machine.ConnectStateObserver(observer);
using var beforeEnterSub = machine.ConnectEventObserver(machine.s2.Enter, eventObserver);

await machine.RaiseEvent(instance, machine.Start); // go to s1
await machine.RaiseEvent(instance, machine.Boom); // go to s2
await machine.RaiseEvent(instance, machine.ToSub); // s2 does not handle ToSub
await machine.RaiseEvent(instance, machine.Boom); // go to s1
await machine.RaiseEvent(instance, machine.ToSub); // go to s21 --> Enter s2 is missing here!
await machine.RaiseEvent(instance, machine.Quit);

Assert.That(eventObserver.Events.Count, Is.EqualTo(2));
}


public class StateData
{
public string CurrentSate { get; set; }
}


public class StateMachine :
AutomatonymousStateMachine<StateData>
{
public StateMachine()
{
InstanceState(x => x.CurrentSate);

SubState(() => s21, s2);

Initially(When(Start).TransitionTo(s1));

WhenEnterAny(x => x.Then(context => Console.WriteLine($"Enter {context.Instance.CurrentSate} ({context.Event.Name}).")));
WhenLeaveAny(x => x.Then(context => Console.WriteLine($"Leave {context.Instance.CurrentSate} ({context.Event.Name}).")));

During(s1,
When(Boom).TransitionTo(s2),
When(ToSub).TransitionTo(s21)
);
During(s2,
When(Boom).TransitionTo(s1)
);

DuringAny(When(Quit).Finalize());

Finally(x => x.Then(context => Console.WriteLine("We're done.")));

OnUnhandledEvent(context => Console.Out.WriteLineAsync($"{context.Instance.CurrentSate} does not handle {context.Event}!"));
}

public State s1 { get; private set; }
public State s2 { get; private set; }
public State s21 { get; private set; }

public Event Start { get; private set; }
public Event Boom { get; private set; }
public Event ToSub { get; private set; }
public Event Quit { get; private set; }
}
}
}

0 comments on commit b50e86f

Please sign in to comment.