diff --git a/GFramework.Core.Tests/State/StateMachineExtensions.cs b/GFramework.Core.Tests/State/StateMachineExtensions.cs new file mode 100644 index 00000000..685471a9 --- /dev/null +++ b/GFramework.Core.Tests/State/StateMachineExtensions.cs @@ -0,0 +1,24 @@ +using System.Reflection; +using GFramework.Core.Abstractions.State; +using GFramework.Core.State; + +namespace GFramework.Core.Tests.State; + +/// +/// 为状态机测试提供仅限断言场景使用的反射辅助方法。 +/// +public static class StateMachineExtensions +{ + /// + /// 检查状态机内部缓存中是否已注册指定类型的状态。 + /// + /// 要检查的状态类型。 + /// 待检查的状态机实例。 + /// 找到对应状态类型时返回 ,否则返回 + public static bool ContainsState(this StateMachine stateMachine) where T : IState + { + return stateMachine.GetType().GetField("States", BindingFlags.NonPublic | BindingFlags.Instance)? + .GetValue(stateMachine) is Dictionary states && + states.ContainsKey(typeof(T)); + } +} diff --git a/GFramework.Core.Tests/State/StateMachineTests.cs b/GFramework.Core.Tests/State/StateMachineTests.cs index 9edfb036..135e242d 100644 --- a/GFramework.Core.Tests/State/StateMachineTests.cs +++ b/GFramework.Core.Tests/State/StateMachineTests.cs @@ -1,4 +1,3 @@ -using System.Reflection; using GFramework.Core.Abstractions.State; using GFramework.Core.State; using NUnit.Framework; @@ -368,237 +367,3 @@ public class StateMachineTests Assert.That(state3.ExitCalled, Is.False); } } - -/// -/// 测试状态类V2版本,实现IState接口用于测试 -/// -public sealed class TestStateV2 : IState -{ - public bool AllowTransition { get; set; } = true; - public bool EnterCalled { get; private set; } - public bool ExitCalled { get; private set; } - public int EnterCallCount { get; private set; } - public int ExitCallCount { get; private set; } - public IState? EnterFrom { get; private set; } - public IState? ExitTo { get; private set; } - - /// - /// 进入状态时的回调方法 - /// - /// 从哪个状态进入 - public void OnEnter(IState? from) - { - EnterCalled = true; - EnterCallCount++; - EnterFrom = from; - } - - /// - /// 离开状态时的回调方法 - /// - /// 离开到哪个状态 - public void OnExit(IState? to) - { - ExitCalled = true; - ExitCallCount++; - ExitTo = to; - } - - /// - /// 判断是否可以转换到目标状态 - /// - /// 目标状态 - /// 是否允许转换 - public bool CanTransitionTo(IState target) - { - return AllowTransition; - } -} - -/// -/// 测试状态类V3版本,实现IState接口用于测试 -/// -public sealed class TestStateV3 : IState -{ - public bool EnterCalled { get; private set; } - public bool ExitCalled { get; private set; } - public int EnterCallCount { get; private set; } - public int ExitCallCount { get; private set; } - public IState? EnterFrom { get; private set; } - public IState? ExitTo { get; private set; } - - /// - /// 进入状态时的回调方法 - /// - /// 从哪个状态进入 - public void OnEnter(IState? from) - { - EnterCalled = true; - EnterCallCount++; - EnterFrom = from; - } - - /// - /// 离开状态时的回调方法 - /// - /// 离开到哪个状态 - public void OnExit(IState? to) - { - ExitCalled = true; - ExitCallCount++; - ExitTo = to; - } - - /// - /// 判断是否可以转换到目标状态 - /// - /// 目标状态 - /// 是否允许转换 - public bool CanTransitionTo(IState target) - { - return true; - } -} - -/// -/// 测试状态类V4版本,实现IState接口用于测试 -/// -public sealed class TestStateV4 : IState -{ - public bool EnterCalled { get; private set; } - public bool ExitCalled { get; private set; } - public int EnterCallCount { get; private set; } - public int ExitCallCount { get; private set; } - public IState? EnterFrom { get; private set; } - public IState? ExitTo { get; private set; } - - /// - /// 进入状态时的回调方法 - /// - /// 从哪个状态进入 - public void OnEnter(IState? from) - { - EnterCalled = true; - EnterCallCount++; - EnterFrom = from; - } - - /// - /// 离开状态时的回调方法 - /// - /// 离开到哪个状态 - public void OnExit(IState? to) - { - ExitCalled = true; - ExitCallCount++; - ExitTo = to; - } - - /// - /// 判断是否可以转换到目标状态 - /// - /// 目标状态 - /// 是否允许转换 - public bool CanTransitionTo(IState target) - { - return true; - } -} - -/// -/// 异步测试状态类,同时实现IState和IAsyncState接口用于测试异步状态功能 -/// -public sealed class TestAsyncState : IState, IAsyncState -{ - public bool AllowTransition { get; set; } = true; - public bool EnterCalled { get; private set; } - public bool ExitCalled { get; private set; } - public int EnterCallCount { get; private set; } - public int ExitCallCount { get; private set; } - public IState? EnterFrom { get; private set; } - public IState? ExitTo { get; private set; } - public int CanTransitionToCallCount { get; private set; } - - /// - /// 异步进入状态时的回调方法 - /// - /// 从哪个状态进入 - public async Task OnEnterAsync(IState? from) - { - await Task.Delay(1).ConfigureAwait(false); - EnterCalled = true; - EnterCallCount++; - EnterFrom = from; - } - - /// - /// 异步离开状态时的回调方法 - /// - /// 离开到哪个状态 - public async Task OnExitAsync(IState? to) - { - await Task.Delay(1).ConfigureAwait(false); - ExitCalled = true; - ExitCallCount++; - ExitTo = to; - } - - /// - /// 异步判断是否可以转换到目标状态 - /// - /// 目标状态 - /// 是否允许转换 - public async Task CanTransitionToAsync(IState target) - { - await Task.Delay(1).ConfigureAwait(false); - CanTransitionToCallCount++; - return AllowTransition; - } - - /// - /// 进入状态时的回调方法(同步版本,抛出异常表示不应被调用) - /// - /// 从哪个状态进入 - public void OnEnter(IState? from) - { - throw new InvalidOperationException("Sync OnEnter should not be called for async state"); - } - - /// - /// 离开状态时的回调方法(同步版本,抛出异常表示不应被调用) - /// - /// 离开到哪个状态 - public void OnExit(IState? to) - { - throw new InvalidOperationException("Sync OnExit should not be called for async state"); - } - - /// - /// 判断是否可以转换到目标状态(同步版本,抛出异常表示不应被调用) - /// - /// 目标状态 - /// 是否允许转换 - public bool CanTransitionTo(IState target) - { - throw new InvalidOperationException("Sync CanTransitionTo should not be called for async state"); - } -} - -/// -/// 状态机扩展方法类 -/// -public static class StateMachineExtensions -{ - /// - /// 检查状态机是否包含指定类型的状态 - /// - /// 要检查的状态类型 - /// 状态机实例 - /// 如果包含指定类型的状态则返回true,否则返回false - public static bool ContainsState(this StateMachine stateMachine) where T : IState - { - return stateMachine.GetType().GetField("States", BindingFlags.NonPublic | BindingFlags.Instance)? - .GetValue(stateMachine) is Dictionary states && - states.ContainsKey(typeof(T)); - } -} diff --git a/GFramework.Core.Tests/State/TestAsyncState.cs b/GFramework.Core.Tests/State/TestAsyncState.cs new file mode 100644 index 00000000..af31b698 --- /dev/null +++ b/GFramework.Core.Tests/State/TestAsyncState.cs @@ -0,0 +1,116 @@ +using GFramework.Core.Abstractions.State; + +namespace GFramework.Core.Tests.State; + +/// +/// 为 提供异步生命周期路径的测试状态。 +/// +public sealed class TestAsyncState : IState, IAsyncState +{ + /// + /// 获取或设置是否允许向目标状态转移。 + /// + public bool AllowTransition { get; set; } = true; + + /// + /// 获取异步进入状态是否已被调用。 + /// + public bool EnterCalled { get; private set; } + + /// + /// 获取异步离开状态是否已被调用。 + /// + public bool ExitCalled { get; private set; } + + /// + /// 获取异步进入回调被调用的次数。 + /// + public int EnterCallCount { get; private set; } + + /// + /// 获取异步离开回调被调用的次数。 + /// + public int ExitCallCount { get; private set; } + + /// + /// 获取最近一次异步进入时的来源状态。 + /// + public IState? EnterFrom { get; private set; } + + /// + /// 获取最近一次异步离开时的目标状态。 + /// + public IState? ExitTo { get; private set; } + + /// + /// 获取异步转移检查被调用的次数。 + /// + public int CanTransitionToCallCount { get; private set; } + + /// + /// 异步记录进入状态的来源状态与调用次数。 + /// + /// 触发进入的来源状态。 + public async Task OnEnterAsync(IState? from) + { + await Task.Delay(1).ConfigureAwait(false); + EnterCalled = true; + EnterCallCount++; + EnterFrom = from; + } + + /// + /// 异步记录离开状态的目标状态与调用次数。 + /// + /// 即将切换到的目标状态。 + public async Task OnExitAsync(IState? to) + { + await Task.Delay(1).ConfigureAwait(false); + ExitCalled = true; + ExitCallCount++; + ExitTo = to; + } + + /// + /// 异步记录转移检查并返回当前是否允许切换。 + /// + /// 目标状态。 + /// 允许切换时返回 ,否则返回 + public async Task CanTransitionToAsync(IState target) + { + await Task.Delay(1).ConfigureAwait(false); + CanTransitionToCallCount++; + return AllowTransition; + } + + /// + /// 同步进入入口不应被异步状态机路径调用。 + /// + /// 触发进入的来源状态。 + /// 总是抛出,表示当前测试状态只允许异步入口。 + public void OnEnter(IState? from) + { + throw new InvalidOperationException("Sync OnEnter should not be called for async state"); + } + + /// + /// 同步离开入口不应被异步状态机路径调用。 + /// + /// 即将切换到的目标状态。 + /// 总是抛出,表示当前测试状态只允许异步入口。 + public void OnExit(IState? to) + { + throw new InvalidOperationException("Sync OnExit should not be called for async state"); + } + + /// + /// 同步转移检查入口不应被异步状态机路径调用。 + /// + /// 目标状态。 + /// 此方法不会正常返回。 + /// 总是抛出,表示当前测试状态只允许异步入口。 + public bool CanTransitionTo(IState target) + { + throw new InvalidOperationException("Sync CanTransitionTo should not be called for async state"); + } +} diff --git a/GFramework.Core.Tests/State/TestStateV2.cs b/GFramework.Core.Tests/State/TestStateV2.cs new file mode 100644 index 00000000..2d2f26d2 --- /dev/null +++ b/GFramework.Core.Tests/State/TestStateV2.cs @@ -0,0 +1,76 @@ +using GFramework.Core.Abstractions.State; + +namespace GFramework.Core.Tests.State; + +/// +/// 为 提供可配置转移结果的同步测试状态。 +/// +public sealed class TestStateV2 : IState +{ + /// + /// 获取或设置是否允许向目标状态转移。 + /// + public bool AllowTransition { get; set; } = true; + + /// + /// 获取进入状态是否已被调用。 + /// + public bool EnterCalled { get; private set; } + + /// + /// 获取离开状态是否已被调用。 + /// + public bool ExitCalled { get; private set; } + + /// + /// 获取进入回调被调用的次数。 + /// + public int EnterCallCount { get; private set; } + + /// + /// 获取离开回调被调用的次数。 + /// + public int ExitCallCount { get; private set; } + + /// + /// 获取最近一次进入时的来源状态。 + /// + public IState? EnterFrom { get; private set; } + + /// + /// 获取最近一次离开时的目标状态。 + /// + public IState? ExitTo { get; private set; } + + /// + /// 记录进入状态时的来源状态与调用次数。 + /// + /// 触发进入的来源状态。 + public void OnEnter(IState? from) + { + EnterCalled = true; + EnterCallCount++; + EnterFrom = from; + } + + /// + /// 记录离开状态时的目标状态与调用次数。 + /// + /// 即将切换到的目标状态。 + public void OnExit(IState? to) + { + ExitCalled = true; + ExitCallCount++; + ExitTo = to; + } + + /// + /// 根据 返回是否允许切换。 + /// + /// 目标状态。 + /// 允许切换时返回 ,否则返回 + public bool CanTransitionTo(IState target) + { + return AllowTransition; + } +} diff --git a/GFramework.Core.Tests/State/TestStateV3.cs b/GFramework.Core.Tests/State/TestStateV3.cs new file mode 100644 index 00000000..9bb05e4c --- /dev/null +++ b/GFramework.Core.Tests/State/TestStateV3.cs @@ -0,0 +1,71 @@ +using GFramework.Core.Abstractions.State; + +namespace GFramework.Core.Tests.State; + +/// +/// 为 提供始终允许切换的同步测试状态。 +/// +public sealed class TestStateV3 : IState +{ + /// + /// 获取进入状态是否已被调用。 + /// + public bool EnterCalled { get; private set; } + + /// + /// 获取离开状态是否已被调用。 + /// + public bool ExitCalled { get; private set; } + + /// + /// 获取进入回调被调用的次数。 + /// + public int EnterCallCount { get; private set; } + + /// + /// 获取离开回调被调用的次数。 + /// + public int ExitCallCount { get; private set; } + + /// + /// 获取最近一次进入时的来源状态。 + /// + public IState? EnterFrom { get; private set; } + + /// + /// 获取最近一次离开时的目标状态。 + /// + public IState? ExitTo { get; private set; } + + /// + /// 记录进入状态时的来源状态与调用次数。 + /// + /// 触发进入的来源状态。 + public void OnEnter(IState? from) + { + EnterCalled = true; + EnterCallCount++; + EnterFrom = from; + } + + /// + /// 记录离开状态时的目标状态与调用次数。 + /// + /// 即将切换到的目标状态。 + public void OnExit(IState? to) + { + ExitCalled = true; + ExitCallCount++; + ExitTo = to; + } + + /// + /// 始终允许切换到目标状态。 + /// + /// 目标状态。 + /// 始终返回 + public bool CanTransitionTo(IState target) + { + return true; + } +} diff --git a/GFramework.Core.Tests/State/TestStateV4.cs b/GFramework.Core.Tests/State/TestStateV4.cs new file mode 100644 index 00000000..50788354 --- /dev/null +++ b/GFramework.Core.Tests/State/TestStateV4.cs @@ -0,0 +1,71 @@ +using GFramework.Core.Abstractions.State; + +namespace GFramework.Core.Tests.State; + +/// +/// 为 保留的附加同步测试状态实现。 +/// +public sealed class TestStateV4 : IState +{ + /// + /// 获取进入状态是否已被调用。 + /// + public bool EnterCalled { get; private set; } + + /// + /// 获取离开状态是否已被调用。 + /// + public bool ExitCalled { get; private set; } + + /// + /// 获取进入回调被调用的次数。 + /// + public int EnterCallCount { get; private set; } + + /// + /// 获取离开回调被调用的次数。 + /// + public int ExitCallCount { get; private set; } + + /// + /// 获取最近一次进入时的来源状态。 + /// + public IState? EnterFrom { get; private set; } + + /// + /// 获取最近一次离开时的目标状态。 + /// + public IState? ExitTo { get; private set; } + + /// + /// 记录进入状态时的来源状态与调用次数。 + /// + /// 触发进入的来源状态。 + public void OnEnter(IState? from) + { + EnterCalled = true; + EnterCallCount++; + EnterFrom = from; + } + + /// + /// 记录离开状态时的目标状态与调用次数。 + /// + /// 即将切换到的目标状态。 + public void OnExit(IState? to) + { + ExitCalled = true; + ExitCallCount++; + ExitTo = to; + } + + /// + /// 始终允许切换到目标状态。 + /// + /// 目标状态。 + /// 始终返回 + public bool CanTransitionTo(IState target) + { + return true; + } +}