using System; using Xunit; using XplorePlane.Models; namespace XplorePlane.Tests.Models { public class StateModelsTests { // ── Default Value Tests ─────────────────────────────────────── [Fact] public void MotionState_Default_AllZeros() { var state = MotionState.Default; Assert.Equal(0, state.XM); Assert.Equal(0, state.YM); Assert.Equal(0, state.ZT); Assert.Equal(0, state.ZD); Assert.Equal(0, state.TiltD); Assert.Equal(0, state.Dist); Assert.Equal(0, state.XMSpeed); Assert.Equal(0, state.YMSpeed); Assert.Equal(0, state.ZTSpeed); Assert.Equal(0, state.ZDSpeed); Assert.Equal(0, state.TiltDSpeed); Assert.Equal(0, state.DistSpeed); } [Fact] public void RaySourceState_Default_IsOffAndZeros() { var state = RaySourceState.Default; Assert.False(state.IsOn); Assert.Equal(0, state.Voltage); Assert.Equal(0, state.Power); } [Fact] public void DetectorState_Default_DisconnectedAndZeros() { var state = DetectorState.Default; Assert.False(state.IsConnected); Assert.False(state.IsAcquiring); Assert.Equal(0, state.FrameRate); Assert.Equal(string.Empty, state.Resolution); } [Fact] public void SystemState_Default_IdleNoError() { var state = SystemState.Default; Assert.Equal(OperationMode.Idle, state.OperationMode); Assert.False(state.HasError); Assert.Equal(string.Empty, state.ErrorMessage); } [Fact] public void CameraState_Default_DisconnectedAndZeros() { var state = CameraState.Default; Assert.False(state.IsConnected); Assert.False(state.IsStreaming); Assert.Null(state.CurrentFrame); Assert.Equal(0, state.Width); Assert.Equal(0, state.Height); Assert.Equal(0, state.FrameRate); } [Fact] public void LinkedViewState_Default_ZeroPositionNotExecuting() { var state = LinkedViewState.Default; Assert.Equal(0, state.TargetPosition.X); Assert.Equal(0, state.TargetPosition.Y); Assert.Equal(0, state.TargetPosition.Z); Assert.False(state.IsExecuting); Assert.Equal(DateTime.MinValue, state.LastRequestTime); } [Fact] public void RecipeExecutionState_Default_IdleAndZeros() { var state = RecipeExecutionState.Default; Assert.Equal(0, state.CurrentStepIndex); Assert.Equal(0, state.TotalSteps); Assert.Equal(RecipeExecutionStatus.Idle, state.Status); Assert.Equal(string.Empty, state.CurrentRecipeName); } // ── Immutability Test ───────────────────────────────────────── [Fact] public void MotionState_WithExpression_ProducesNewInstance() { var original = MotionState.Default; var modified = original with { XM = 100 }; // New instance is different from original Assert.NotSame(original, modified); Assert.Equal(100, modified.XM); // Original is unchanged Assert.Equal(0, original.XM); } // ── CalibrationMatrix Transform Tests ───────────────────────── [Fact] public void CalibrationMatrix_Transform_CorrectCalculation() { // Known matrix: scaling X by 2, Y by 3, with offsets var matrix = new CalibrationMatrix( M11: 2, M12: 0, M13: 10, M21: 0, M22: 3, M23: 20, M31: 0, M32: 0, M33: 0 ); var (x, y, z) = matrix.Transform(pixelX: 5, pixelY: 8); // x = 2*5 + 0*8 + 10 = 20 Assert.Equal(20, x); // y = 0*5 + 3*8 + 20 = 44 Assert.Equal(44, y); // z = 0*5 + 0*8 + 0 = 0 Assert.Equal(0, z); } [Fact] public void CalibrationMatrix_Transform_IdentityMatrix() { // Identity-like matrix: should return (pixelX, pixelY, 0) approximately var identity = new CalibrationMatrix( M11: 1, M12: 0, M13: 0, M21: 0, M22: 1, M23: 0, M31: 0, M32: 0, M33: 0 ); var (x, y, z) = identity.Transform(pixelX: 42.5, pixelY: 99.1); Assert.Equal(42.5, x, precision: 10); Assert.Equal(99.1, y, precision: 10); Assert.Equal(0, z, precision: 10); } } }