using System; using Xunit; using Xunit.Abstractions; using XplorePlane.Models; namespace XplorePlane.Tests.Models { public class StateModelsTests { private readonly ITestOutputHelper _output; public StateModelsTests(ITestOutputHelper output) { _output = output; } // ── Default Value Tests ─────────────────────────────────────── [Fact] public void MotionState_Default_AllZeros() { var state = MotionState.Default; _output.WriteLine($"MotionState.Default: XM={state.XM}, YM={state.YM}, ZT={state.ZT}, ZD={state.ZD}, TiltD={state.TiltD}, Dist={state.Dist}"); _output.WriteLine($" Speeds: XM={state.XMSpeed}, YM={state.YMSpeed}, ZT={state.ZTSpeed}, ZD={state.ZDSpeed}, TiltD={state.TiltDSpeed}, Dist={state.DistSpeed}"); 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; _output.WriteLine($"RaySourceState.Default: IsOn={state.IsOn}, Voltage={state.Voltage}, Power={state.Power}"); Assert.False(state.IsOn); Assert.Equal(0, state.Voltage); Assert.Equal(0, state.Power); } [Fact] public void DetectorState_Default_DisconnectedAndZeros() { var state = DetectorState.Default; _output.WriteLine($"DetectorState.Default: IsConnected={state.IsConnected}, IsAcquiring={state.IsAcquiring}, FrameRate={state.FrameRate}, Resolution='{state.Resolution}'"); 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; _output.WriteLine($"SystemState.Default: OperationMode={state.OperationMode}, HasError={state.HasError}, ErrorMessage='{state.ErrorMessage}'"); 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; _output.WriteLine($"CameraState.Default: IsConnected={state.IsConnected}, IsStreaming={state.IsStreaming}, CurrentFrame={state.CurrentFrame}, Width={state.Width}, Height={state.Height}, FrameRate={state.FrameRate}"); 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; _output.WriteLine($"LinkedViewState.Default: TargetPosition=({state.TargetPosition.X}, {state.TargetPosition.Y}, {state.TargetPosition.Z}), IsExecuting={state.IsExecuting}, LastRequestTime={state.LastRequestTime}"); 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; _output.WriteLine($"RecipeExecutionState.Default: CurrentStepIndex={state.CurrentStepIndex}, TotalSteps={state.TotalSteps}, Status={state.Status}, CurrentRecipeName='{state.CurrentRecipeName}'"); 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 }; _output.WriteLine($"Original.XM={original.XM}, Modified.XM={modified.XM}, SameRef={ReferenceEquals(original, modified)}"); // 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); _output.WriteLine($"Matrix Transform(5, 8): x={x}, y={y}, z={z} (expected: 20, 44, 0)"); // 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); _output.WriteLine($"Identity Transform(42.5, 99.1): x={x}, y={y}, z={z}"); Assert.Equal(42.5, x, precision: 10); Assert.Equal(99.1, y, precision: 10); Assert.Equal(0, z, precision: 10); } } }