using System; using XplorePlane.Models; using Xunit; using Xunit.Abstractions; 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: StageX={state.StageX}, StageY={state.StageY}, SourceZ={state.SourceZ}, DetectorZ={state.DetectorZ}, DetectorSwing={state.DetectorSwing}, FDD={state.FDD}"); _output.WriteLine($" Speeds: StageX={state.StageXSpeed}, StageY={state.StageYSpeed}, SourceZ={state.SourceZSpeed}, DetectorZ={state.DetectorZSpeed}, DetectorSwing={state.DetectorSwingSpeed}, FDD={state.FDDSpeed}"); Assert.Equal(0, state.StageX); Assert.Equal(0, state.StageY); Assert.Equal(0, state.SourceZ); Assert.Equal(0, state.DetectorZ); Assert.Equal(0, state.DetectorSwing); Assert.Equal(0, state.FDD); Assert.Equal(0, state.StageXSpeed); Assert.Equal(0, state.StageYSpeed); Assert.Equal(0, state.SourceZSpeed); Assert.Equal(0, state.DetectorZSpeed); Assert.Equal(0, state.DetectorSwingSpeed); Assert.Equal(0, state.FDDSpeed); Assert.Equal(0, state.StageRotation); Assert.Equal(0, state.FixtureRotation); Assert.Equal(0, state.FOD); Assert.Equal(0, state.Magnification); } [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 { StageX = 100 }; _output.WriteLine($"Original.StageX={original.StageX}, Modified.StageX={modified.StageX}, SameRef={ReferenceEquals(original, modified)}"); // New instance is different from original Assert.NotSame(original, modified); Assert.Equal(100, modified.StageX); // Original is unchanged Assert.Equal(0, original.StageX); } // ── 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); } } }