using System; using System.Windows; using Moq; using Serilog; using Xunit; using XP.Hardware.RaySource.Services; using XplorePlane.Models; using XplorePlane.Services.AppState; namespace XplorePlane.Tests.Services { /// /// AppStateService 单元测试。 /// 验证默认状态值、Dispose 后行为、null 参数校验、CalibrationMatrix 缺失时的错误处理。 /// public class AppStateServiceTests : IDisposable { private readonly AppStateService _service; private readonly Mock _mockRaySource; private readonly Mock _mockLogger; public AppStateServiceTests() { // Ensure WPF Application exists for Dispatcher if (Application.Current == null) { new Application(); } _mockRaySource = new Mock(); _mockLogger = new Mock(); _service = new AppStateService(_mockRaySource.Object, _mockLogger.Object); } public void Dispose() { _service.Dispose(); } // ── 默认状态值验证 ── [Fact] public void DefaultState_MotionState_IsDefault() { Assert.Same(MotionState.Default, _service.MotionState); } [Fact] public void DefaultState_RaySourceState_IsDefault() { Assert.Same(RaySourceState.Default, _service.RaySourceState); } [Fact] public void DefaultState_SystemState_IsDefault() { Assert.Same(SystemState.Default, _service.SystemState); } [Fact] public void DefaultState_CalibrationMatrix_IsNull() { Assert.Null(_service.CalibrationMatrix); } // ── null 参数抛出 ArgumentNullException ── [Fact] public void UpdateMotionState_NullArgument_ThrowsArgumentNullException() { Assert.Throws(() => _service.UpdateMotionState(null!)); } [Fact] public void UpdateRaySourceState_NullArgument_ThrowsArgumentNullException() { Assert.Throws(() => _service.UpdateRaySourceState(null!)); } [Fact] public void UpdateDetectorState_NullArgument_ThrowsArgumentNullException() { Assert.Throws(() => _service.UpdateDetectorState(null!)); } [Fact] public void UpdateSystemState_NullArgument_ThrowsArgumentNullException() { Assert.Throws(() => _service.UpdateSystemState(null!)); } // ── Dispose 后 Update 被忽略 ── [Fact] public void Dispose_ThenUpdate_IsIgnored() { var originalState = _service.MotionState; _service.Dispose(); // Should not throw, and state should remain unchanged var newState = new MotionState(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); _service.UpdateMotionState(newState); Assert.Same(originalState, _service.MotionState); } // ── CalibrationMatrix 为 null 时 RequestLinkedView 设置错误状态 ── [Fact] public void RequestLinkedView_NoCalibrationMatrix_SetsErrorState() { // CalibrationMatrix is null by default Assert.Null(_service.CalibrationMatrix); _service.RequestLinkedView(100.0, 200.0); Assert.True(_service.SystemState.HasError); Assert.NotEmpty(_service.SystemState.ErrorMessage); } } }