using System; using System.Collections.Generic; using System.Linq; using Moq; using Prism.Events; using XP.Common.Logging.Interfaces; using XP.Hardware.MotionControl.Abstractions; using XP.Hardware.MotionControl.Abstractions.Enums; using Xunit; using XplorePlane.Models; using XplorePlane.Services.Cnc; using XplorePlane.Services.Cnc.Matrix; using XplorePlane.Services.Dialogs; using XplorePlane.ViewModels.Cnc; namespace XplorePlane.Tests.ViewModels { public class MatrixEditorViewModelTests { [Fact] public void Constructor_CreatesTwoByTwoLayoutByDefault() { var fixture = CreateFixture(); Assert.Equal(2, fixture.ViewModel.Rows); Assert.Equal(2, fixture.ViewModel.Columns); Assert.Equal(4, fixture.ViewModel.Cells.Count); Assert.Equal(new[] { 1, 4 }, fixture.ViewModel.TeachPoints.Select(point => point.Position)); } [Fact] public void RecordCurrentPosition_RefreshesMotionAxesAndRecordsLatestCoordinates() { var fixture = CreateFixture(stageXmm: 12.3456, stageYmm: -3.2546); var teachPoint = fixture.ViewModel.CurrentTeachPoint; fixture.ViewModel.RecordCurrentPositionCommand.Execute(); fixture.StageX.Verify(axis => axis.UpdateStatus(), Times.Once); fixture.StageY.Verify(axis => axis.UpdateStatus(), Times.Once); Assert.True(teachPoint.HasRecorded); Assert.Equal(12.346, teachPoint.RecordedX); Assert.Equal(-3.255, teachPoint.RecordedY); Assert.Equal("X:12.346 Y:-3.255 mm", teachPoint.CoordinateLabel); } [Fact] public void AutoGenerate_UsesRecordedMillimeterCoordinatesWithoutUnitScaling() { var fixture = CreateFixture(stageXmm: 10.1234, stageYmm: 20.1234); fixture.ViewModel.RecordCurrentPositionCommand.Execute(); fixture.StageX.SetupGet(axis => axis.ActualPosition).Returns(11.2345); fixture.StageY.SetupGet(axis => axis.ActualPosition).Returns(25.6789); fixture.ViewModel.RecordCurrentPositionCommand.Execute(); fixture.ViewModel.AutoGenerateCommand.Execute(); var topRight = fixture.ViewModel.Cells[1]; var bottomLeft = fixture.ViewModel.Cells[2]; var bottomRight = fixture.ViewModel.Cells[3]; Assert.Equal(1.112, topRight.OffsetX); Assert.Equal(0, topRight.OffsetY); Assert.Equal(0, bottomLeft.OffsetX); Assert.Equal(5.556, bottomLeft.OffsetY); Assert.Equal(1.112, bottomRight.OffsetX); Assert.Equal(5.556, bottomRight.OffsetY); Assert.Equal("X:10.123 Y:25.679", bottomLeft.CoordinateLabel); Assert.Equal("X:11.235 Y:25.679", bottomRight.CoordinateLabel); } [Fact] public void CellCommands_RecordAdditionalPositionAndToggleEnabledState() { var fixture = CreateFixture(stageXmm: 7.1234, stageYmm: 8.5678); var targetCell = fixture.ViewModel.Cells[1]; fixture.ViewModel.RecordCellPositionCommand.Execute(targetCell); var additionalPoint = Assert.Single( fixture.ViewModel.TeachPoints, point => point.Position == 2); Assert.True(additionalPoint.IsTaught); Assert.Equal(7.123, additionalPoint.RecordedX); Assert.Equal(8.568, additionalPoint.RecordedY); Assert.Equal(MatrixCellTeachState.Taught, fixture.ViewModel.Cells[1].TeachState); fixture.ViewModel.ToggleCellCommand.Execute(fixture.ViewModel.Cells[1]); Assert.False(fixture.ViewModel.Cells[1].IsEnabled); } private static Fixture CreateFixture(double stageXmm = 0, double stageYmm = 0) { var matrixService = new Mock(); matrixService .Setup(service => service.CreateLayout( It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) .Returns(CreateLayout); matrixService .Setup(service => service.ToggleCellEnabled( It.IsAny(), It.IsAny(), It.IsAny())) .Returns((layout, row, column) => { var cells = layout.Cells .Select(cell => cell.Row == row && cell.Column == column ? cell with { IsEnabled = !cell.IsEnabled } : cell) .ToList() .AsReadOnly(); return layout with { Cells = cells }; }); var stageX = new Mock(); stageX.SetupGet(axis => axis.ActualPosition).Returns(stageXmm); var stageY = new Mock(); stageY.SetupGet(axis => axis.ActualPosition).Returns(stageYmm); var motionSystem = new Mock(); motionSystem.Setup(system => system.GetLinearAxis(AxisId.StageX)).Returns(stageX.Object); motionSystem.Setup(system => system.GetLinearAxis(AxisId.StageY)).Returns(stageY.Object); var logger = new Mock(); logger.Setup(service => service.ForModule()).Returns(logger.Object); var viewModel = new MatrixEditorViewModel( matrixService.Object, Mock.Of(), Mock.Of(), motionSystem.Object, Mock.Of(), logger.Object, Mock.Of()); return new Fixture(viewModel, stageX, stageY); } private static MatrixLayout CreateLayout(int rows, int columns, double rowSpacing, double columnSpacing) { var cells = new List(); for (var row = 0; row < rows; row++) { for (var column = 0; column < columns; column++) { cells.Add(new MatrixCell( row, column, column * columnSpacing, row * rowSpacing, true, MatrixCellStatus.NotExecuted, null)); } } return new MatrixLayout( Guid.NewGuid(), rows, columns, rowSpacing, columnSpacing, 0, 0, string.Empty, cells.AsReadOnly()); } private sealed record Fixture( MatrixEditorViewModel ViewModel, Mock StageX, Mock StageY); } }