using System.Reflection;
using GFramework.Core.Abstractions.state;
using GFramework.Core.state;
using NUnit.Framework;
namespace GFramework.Core.Tests.state;
///
/// 测试状态机功能的单元测试类
///
[TestFixture]
public class StateMachineTests
{
///
/// 在每个测试方法执行前初始化状态机实例
///
[SetUp]
public void SetUp()
{
_stateMachine = new StateMachine();
}
private StateMachine _stateMachine = null!;
///
/// 验证当没有活动状态时,当前状态应为null
///
[Test]
public void Current_Should_BeNull_When_NoState_Active()
{
Assert.That(_stateMachine.Current, Is.Null);
}
///
/// 验证注册状态后,状态会被添加到状态字典中
///
[Test]
public void Register_Should_AddState_To_StatesDictionary()
{
var state = new TestStateV2();
_stateMachine.Register(state);
Assert.That(_stateMachine.ContainsState(), Is.True);
}
///
/// 验证ChangeTo方法能够正确设置当前状态
///
[Test]
public void ChangeTo_Should_SetCurrentState()
{
var state = new TestStateV2();
_stateMachine.Register(state);
_stateMachine.ChangeTo();
Assert.That(_stateMachine.Current, Is.SameAs(state));
}
///
/// 验证ChangeTo方法会调用OnEnter回调
///
[Test]
public void ChangeTo_Should_Invoke_OnEnter()
{
var state = new TestStateV2();
_stateMachine.Register(state);
_stateMachine.ChangeTo();
Assert.That(state.EnterCalled, Is.True);
Assert.That(state.EnterFrom, Is.Null);
}
///
/// 验证当存在当前状态时,切换到新状态会调用原状态的OnExit回调
///
[Test]
public void ChangeTo_When_CurrentStateExists_Should_Invoke_OnExit()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo();
_stateMachine.ChangeTo();
Assert.That(state1.ExitCalled, Is.True);
Assert.That(state1.ExitTo, Is.SameAs(state2));
}
///
/// 验证当存在当前状态时,切换到新状态会调用新状态的OnEnter回调
///
[Test]
public void ChangeTo_When_CurrentStateExists_Should_Invoke_OnEnter()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo();
_stateMachine.ChangeTo();
Assert.That(state2.EnterCalled, Is.True);
Assert.That(state2.EnterFrom, Is.SameAs(state1));
}
///
/// 验证切换到相同状态时不应调用回调方法
///
[Test]
public void ChangeTo_ToSameState_Should_NotInvoke_Callbacks()
{
var state = new TestStateV2();
_stateMachine.Register(state);
_stateMachine.ChangeTo();
var enterCount = state.EnterCallCount;
var exitCount = state.ExitCallCount;
_stateMachine.ChangeTo();
Assert.That(state.EnterCallCount, Is.EqualTo(enterCount));
Assert.That(state.ExitCallCount, Is.EqualTo(exitCount));
}
///
/// 验证切换到未注册状态时应抛出InvalidOperationException异常
///
[Test]
public void ChangeTo_ToUnregisteredState_Should_ThrowInvalidOperationException()
{
Assert.Throws(() => _stateMachine.ChangeTo());
}
///
/// 验证当状态未注册时CanChangeTo方法应返回false
///
[Test]
public void CanChangeTo_WhenStateNotRegistered_Should_ReturnFalse()
{
var result = _stateMachine.CanChangeTo();
Assert.That(result, Is.False);
}
///
/// 验证当状态已注册时CanChangeTo方法应返回true
///
[Test]
public void CanChangeTo_WhenStateRegistered_Should_ReturnTrue()
{
var state = new TestStateV2();
_stateMachine.Register(state);
var result = _stateMachine.CanChangeTo();
Assert.That(result, Is.True);
}
///
/// 验证当当前状态拒绝转换时CanChangeTo方法应返回false
///
[Test]
public void CanChangeTo_WhenCurrentStateDeniesTransition_Should_ReturnFalse()
{
var state1 = new TestStateV2 { AllowTransition = false };
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo();
var result = _stateMachine.CanChangeTo();
Assert.That(result, Is.False);
}
///
/// 验证当当前状态拒绝转换时不应发生状态变化
///
[Test]
public void ChangeTo_WhenCurrentStateDeniesTransition_Should_NotChange()
{
var state1 = new TestStateV2 { AllowTransition = false };
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo();
var oldState = _stateMachine.Current;
_stateMachine.ChangeTo();
Assert.That(_stateMachine.Current, Is.SameAs(oldState));
Assert.That(_stateMachine.Current, Is.SameAs(state1));
Assert.That(state2.EnterCalled, Is.False);
}
///
/// 验证注销状态后应从字典中移除该状态
///
[Test]
public void Unregister_Should_RemoveState_FromDictionary()
{
var state = new TestStateV2();
_stateMachine.Register(state);
_stateMachine.Unregister();
Assert.That(_stateMachine.ContainsState(), Is.False);
}
///
/// 验证当活动状态被注销时应调用OnExit并清除当前状态
///
[Test]
public void Unregister_WhenStateIsActive_Should_Invoke_OnExit_AndClearCurrent()
{
var state = new TestStateV2();
_stateMachine.Register(state);
_stateMachine.ChangeTo();
_stateMachine.Unregister();
Assert.That(state.ExitCalled, Is.True);
Assert.That(state.ExitTo, Is.Null);
Assert.That(_stateMachine.Current, Is.Null);
}
///
/// 验证当非活动状态被注销时不应调用OnExit
///
[Test]
public void Unregister_WhenStateNotActive_Should_Not_Invoke_OnExit()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.ChangeTo();
_stateMachine.Unregister();
Assert.That(state1.ExitCalled, Is.False);
Assert.That(_stateMachine.Current, Is.SameAs(state1));
}
///
/// 验证多次状态转换应正确调用回调方法
///
[Test]
public void MultipleStateChanges_Should_Invoke_Callbacks_Correctly()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
var state3 = new TestStateV4();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.Register(state3);
_stateMachine.ChangeTo();
_stateMachine.ChangeTo();
_stateMachine.ChangeTo();
Assert.That(state1.EnterCalled, Is.True);
Assert.That(state1.ExitCalled, Is.True);
Assert.That(state2.EnterCalled, Is.True);
Assert.That(state2.ExitCalled, Is.True);
Assert.That(state3.EnterCalled, Is.True);
Assert.That(state3.ExitCalled, Is.False);
}
///
/// 验证ChangeTo方法应遵循CanTransitionTo逻辑
///
[Test]
public void ChangeTo_Should_Respect_CanTransitionTo_Logic()
{
var state1 = new TestStateV2();
var state2 = new TestStateV3();
var state3 = new TestStateV4();
_stateMachine.Register(state1);
_stateMachine.Register(state2);
_stateMachine.Register(state3);
_stateMachine.ChangeTo();
_stateMachine.ChangeTo();
Assert.That(state1.EnterCalled, Is.True);
Assert.That(state1.ExitCalled, Is.True);
Assert.That(state2.EnterCalled, Is.True);
}
}
///
/// 测试状态类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;
}
}
///
/// 状态机扩展方法类
///
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));
}
}