Skip to content

Commit

Permalink
Merge pull request #51 from bazyleu/feature/state-machine-updates
Browse files Browse the repository at this point in the history
Updates state machine error handling, improve tests, update README.md
  • Loading branch information
bazyleu authored Sep 14, 2024
2 parents a9af1a0 + b7f71bd commit 5f004c0
Show file tree
Hide file tree
Showing 19 changed files with 249 additions and 33 deletions.
3 changes: 1 addition & 2 deletions Assets/UniState/Runtime/Core/State/SubStatesContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ public async UniTask<StateTransitionInfo> Execute(CancellationToken token)
{
if (List.Count == 0)
{
//TODO: Add custom exception
throw new Exception("No SubStates for execution");
throw new InvalidOperationException("No SubStates for execution");
}

StateTransitionInfo result;
Expand Down
15 changes: 7 additions & 8 deletions Assets/UniState/Runtime/Core/StateMachine/StateMachine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,8 @@ public virtual async UniTask Execute<TState, TPayload>(TPayload payload, Cancell
await ExecuteInternal(_transitionFactory.CreateStateTransition<TState, TPayload>(payload), token);
}

protected virtual void OnError(Exception exception, StateMachineErrorType phase)
protected virtual void HandleError(StateMachineErrorData errorData)
{
//Add Type (state type) to signature

//Call Handler
}

private async UniTask ExecuteInternal(StateTransitionInfo initialTransition, CancellationToken token)
Expand Down Expand Up @@ -77,7 +74,7 @@ private async UniTask ExecuteInternal(StateTransitionInfo initialTransition, Can
}
catch (Exception e)
{
OnError(e, StateMachineErrorType.StateMachineFail);
ProcessError(new StateMachineErrorData(e, StateMachineErrorType.StateMachineFail));
}
finally
{
Expand Down Expand Up @@ -148,7 +145,7 @@ private async UniTask<StateTransitionInfo> ExecuteSafe(IExecutableState state, C
}
catch (Exception e)
{
OnError(e, StateMachineErrorType.StateExecuting);
ProcessError(new StateMachineErrorData(e, StateMachineErrorType.StateExecuting, state));
}

return transitionInfo;
Expand All @@ -167,7 +164,7 @@ private async UniTask InitializeSafe(IExecutableState state, CancellationToken t
}
catch (Exception e)
{
OnError(e, StateMachineErrorType.StateInitializing);
ProcessError(new StateMachineErrorData(e, StateMachineErrorType.StateInitializing, state));
}
}

Expand All @@ -184,12 +181,14 @@ private async UniTask ExitAndDisposeSafe(IExecutableState state, CancellationTok
}
catch (Exception e)
{
OnError(e, StateMachineErrorType.StateExiting);
ProcessError(new StateMachineErrorData(e, StateMachineErrorType.StateExiting, state));
}
finally
{
state.Dispose();
}
}

private void ProcessError(StateMachineErrorData errorData) => HandleError(errorData);
}
}
18 changes: 18 additions & 0 deletions Assets/UniState/Runtime/Core/StateMachine/StateMachineErrorData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace UniState
{
public class StateMachineErrorData
{
public Exception Exception { get; }
public StateMachineErrorType ErrorType { get; }
public IExecutableState State { get; }

public StateMachineErrorData(Exception exception, StateMachineErrorType errorType, IExecutableState state = null)
{
Exception = exception;
ErrorType = errorType;
State = state;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@ protected VerifiableStateMachine(ExecutionLogger logger)
_logger = logger;
}

protected override void OnError(Exception exception, StateMachineErrorType phase)
protected override void HandleError(StateMachineErrorData errorData)
{
throw new Exception($"StateMachine OnError. Current log: {_logger.FinishLogging()}", exception);
throw new Exception($"StateMachine HandleError. Current log: {_logger.FinishLogging()}", errorData.Exception);
}

public void Verify()
{
Assert.AreEqual(ExpectedLog, _logger.FinishLogging());
var actualLog = _logger.FinishLogging();
Assert.AreEqual(ExpectedLog, actualLog);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public override async UniTask<StateTransitionInfo> Execute(CancellationToken tok

_goBackFlags.ExecutedState1 = true;

return Transition.GoTo<StateGoBack2>();
return Transition.GoTo<StateGoBack2, int>(42);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

namespace UniStateTests.PlayMode.GoBackTests.Infrastructure
{
internal class StateGoBack2 : StateBase
internal class StateGoBack2 : StateBase<int>
{
private readonly ExecutionLogger _logger;
private readonly GoBackFlagsData _goBackFlags;
Expand All @@ -18,7 +18,7 @@ public StateGoBack2(ExecutionLogger logger, GoBackFlagsData goBackFlags)

public override async UniTask<StateTransitionInfo> Execute(CancellationToken token)
{
_logger.LogStep("StateGoBack2", "Execute");
_logger.LogStep("StateGoBack2", $"Execute:{Payload}");

await UniTask.Yield();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ namespace UniStateTests.PlayMode.GoBackTests.Infrastructure
internal class StateMachineGoBack : VerifiableStateMachine
{
protected override string ExpectedLog =>
"StateGoBack1 (Execute) -> StateGoBack2 (Execute) -> StateGoBack3 (Execute) -> " +
"StateGoBack2 (Execute) -> StateGoBack1 (Execute)";
"StateGoBack1 (Execute) -> StateGoBack2 (Execute:42) -> StateGoBack3 (Execute) -> " +
"StateGoBack2 (Execute:42) -> StateGoBack1 (Execute)";

public StateMachineGoBack(ExecutionLogger logger) : base(logger)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace UniStateTests.PlayMode.GoToStateTests
{
[TestFixture]
internal class VContainerIntegrationTests : VContainerTestsBase
internal class GoToVContainerTests : VContainerTestsBase
{
[UnityTest]
public IEnumerator RunChaneOfState_ExitFromChain_ChainExecutedCorrectly() => UniTask.ToCoroutine(async () =>
Expand All @@ -32,6 +32,10 @@ protected override void SetupBindings(IContainerBuilder builder)
builder.RegisterState<CompositeStateGoTo6>();
builder.RegisterState<SubStateGoToX6A>();
builder.RegisterState<SubStateGoToX6B>();
builder.RegisterState<CompositeStateGoTo7>();
builder.RegisterState<SubStateGoToX7A>();
builder.RegisterState<SubStateGoToX7B>();
builder.RegisterState<StateGoTo8>();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ protected override void SetupBindings(DiContainer container)
container.BindState<CompositeStateGoTo6>();
container.BindState<SubStateGoToX6A>();
container.BindState<SubStateGoToX6B>();
container.BindState<CompositeStateGoTo7>();
container.BindState<SubStateGoToX7A>();
container.BindState<SubStateGoToX7B>();
container.BindState<StateGoTo8>();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ public override async UniTask<StateTransitionInfo> Execute(CancellationToken tok
{
_logger.LogStep("SubStateGoToX6A", "Execute");

await UniTask.Yield();
await UniTask.Yield();
await UniTask.Yield(token);
await UniTask.Yield(token);

return Transition.GoToExit();
return Transition.GoTo<CompositeStateGoTo7, CompositeStatePayload>(new CompositeStatePayload(true));
}
}

Expand All @@ -42,12 +42,13 @@ public SubStateGoToX6B(ExecutionLogger logger)

public override async UniTask<StateTransitionInfo> Execute(CancellationToken token)
{
await UniTask.Yield();
await UniTask.Yield(token);

_logger.LogStep("SubStateGoToX6B", "Execute");

await UniTask.Yield();
await UniTask.Yield();
await UniTask.Yield(token);
await UniTask.Yield(token);
await UniTask.Yield(token);

return Transition.GoToExit();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System.Threading;
using Cysharp.Threading.Tasks;
using UniState;
using UniStateTests.Common;

namespace UniStateTests.PlayMode.GoToStateTests.Infrastructure
{
internal class CompositeStateGoTo7: DefaultCompositeState<CompositeStatePayload>
{

}

internal class SubStateGoToX7A : SubStateBase<CompositeStateGoTo7, CompositeStatePayload>
{
private readonly ExecutionLogger _logger;

public SubStateGoToX7A(ExecutionLogger logger)
{
_logger = logger;
}

public override async UniTask<StateTransitionInfo> Execute(CancellationToken token)
{
_logger.LogStep("SubStateGoToX7A", $"Execute:{Payload.DelayFirstSubState}");

if (Payload.DelayFirstSubState)
{
await UniTask.Yield(token);
await UniTask.Yield(token);
await UniTask.Yield(token);
await UniTask.Yield(token);
await UniTask.Yield(token);
}

await UniTask.Yield(token);
await UniTask.Yield(token);

return Transition.GoTo<IStateGoTo8, bool>(true);
}
}

internal class SubStateGoToX7B : SubStateBase<CompositeStateGoTo7, CompositeStatePayload>
{
private readonly ExecutionLogger _logger;

public SubStateGoToX7B(ExecutionLogger logger)
{
_logger = logger;
}

public override async UniTask<StateTransitionInfo> Execute(CancellationToken token)
{
await UniTask.Yield(token);

_logger.LogStep("SubStateGoToX7B", $"Execute:{Payload.DelayFirstSubState}");

await UniTask.Yield(token);
await UniTask.Yield(token);

return Transition.GoTo<StateGoTo8, bool>(false);
}
}

internal class CompositeStatePayload
{
public bool DelayFirstSubState { get; }

public CompositeStatePayload(bool delayFirstSubState)
{
DelayFirstSubState = delayFirstSubState;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
using System.Threading;
using Cysharp.Threading.Tasks;
using UniState;
using UniStateTests.Common;

namespace UniStateTests.PlayMode.GoToStateTests.Infrastructure
{
internal interface IStateGoTo8 : IState<bool>
{
}

internal class StateGoTo8 : StateBase<bool>, IStateGoTo8
{
private readonly ExecutionLogger _logger;

public StateGoTo8(ExecutionLogger logger)
{
_logger = logger;
}

public override UniTask<StateTransitionInfo> Execute(CancellationToken token)
{
_logger.LogStep("StateGoTo8", $"Execute:{Payload}");

if (Payload)
{
return UniTask.FromResult(Transition.GoToExit());
}

return UniTask.FromResult(Transition.GoTo<CompositeStateGoTo7, CompositeStatePayload>(new CompositeStatePayload(false)));
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ namespace UniStateTests.PlayMode.GoToStateTests.Infrastructure
{
internal class StateMachineGoToState : VerifiableStateMachine
{
protected override string ExpectedLog =>
"StateGoTo1 (Execute) -> StateGoTo2 (Execute) -> StateGoTo3 (Execute) -> " +
"StateGoTo4 (Execute) -> StateGoTo5 (Execute:42) -> SubStateGoToX6A (Execute) -> SubStateGoToX6B (Execute) -> " +
"SubStateGoToX7A (Execute:True) -> SubStateGoToX7B (Execute:True) -> StateGoTo8 (Execute:False) -> " +
"SubStateGoToX7A (Execute:False) -> SubStateGoToX7B (Execute:False) -> StateGoTo8 (Execute:True)";

public StateMachineGoToState(ExecutionLogger logger) : base(logger)
{
}

protected override string ExpectedLog =>
"StateGoTo1 (Execute) -> StateGoTo2 (Execute) -> StateGoTo3 (Execute) -> " +
"StateGoTo4 (Execute) -> StateGoTo5 (Execute:42) -> SubStateGoToX6A (Execute) -> SubStateGoToX6B (Execute)";
}
}
Loading

0 comments on commit 5f004c0

Please sign in to comment.