// Feature: cnc-run-execution, Property 11: 节点执行状态转换正确性 // Validates: Requirements 6.1, 6.2 using System; using System.Collections.Generic; using System.ComponentModel; using FsCheck; using FsCheck.Fluent; using FsCheck.Xunit; using XplorePlane.Models; using XplorePlane.ViewModels.Cnc; using Xunit; namespace XplorePlane.Tests.ViewModels { public class CncNodeViewModelTests { [Fact] public void SavePosition_SaveImage_CanBeUpdated() { var node = new SavePositionNode(Guid.NewGuid(), 0, "Pos_0", MotionState.Default, SaveImage: false); var vm = new CncNodeViewModel(node, (_, __) => { }); vm.SaveImage = true; var updatedNode = Assert.IsType(vm.Model); Assert.True(vm.SaveImage); Assert.True(updatedNode.SaveImage); } [Property(MaxTest = 100)] public Property ExecutionState_TransitionsProduceCorrectBoolProperties() { var gen = from xm in ArbMap.Default.GeneratorFor() from ym in ArbMap.Default.GeneratorFor() select new ReferencePointNode( Guid.NewGuid(), 0, "TestNode", xm, ym, 0, 0, 0, 0, false, 0, 0); return Prop.ForAll( gen.ToArbitrary(), node => { var vm = new CncNodeViewModel(node, (_, __) => { }); vm.ExecutionState = NodeExecutionState.Running; bool runningOk = vm.IsRunningNode && !vm.IsSucceededNode && !vm.IsFailedNode; vm.ExecutionState = NodeExecutionState.Succeeded; bool succeededOk = !vm.IsRunningNode && vm.IsSucceededNode && !vm.IsFailedNode; vm.ExecutionState = NodeExecutionState.Failed; bool failedOk = !vm.IsRunningNode && !vm.IsSucceededNode && vm.IsFailedNode; vm.ExecutionState = NodeExecutionState.Idle; bool idleOk = !vm.IsRunningNode && !vm.IsSucceededNode && !vm.IsFailedNode; return runningOk && succeededOk && failedOk && idleOk; }); } #region ManualImagePath Binding Tests - Validates: Requirements 2.4 [Fact] public void BrowseImageCommand_IsNotNull_AndCanExecute() { // Arrange var node = new SavePositionNode(Guid.NewGuid(), 0, "Pos_0", MotionState.Default); var vm = new CncNodeViewModel(node, (_, __) => { }); // Act & Assert Assert.NotNull(vm.BrowseImageCommand); Assert.True(vm.BrowseImageCommand.CanExecute(null)); } [Fact] public void ManualImagePath_Set_RaisesPropertyChangedNotification() { // Arrange var node = new SavePositionNode(Guid.NewGuid(), 0, "Pos_0", MotionState.Default); var vm = new CncNodeViewModel(node, (_, __) => { }); var changedProperties = new List(); ((INotifyPropertyChanged)vm).PropertyChanged += (_, e) => changedProperties.Add(e.PropertyName); // Act vm.ManualImagePath = @"C:\Images\test.bmp"; // Assert Assert.Contains(nameof(vm.ManualImagePath), changedProperties); } [Fact] public void ManualImagePath_Getter_ReturnsValueFromUnderlyingModel() { // Arrange var expectedPath = @"D:\TestImages\sample.png"; var node = new SavePositionNode(Guid.NewGuid(), 0, "Pos_0", MotionState.Default, ManualImagePath: expectedPath); var vm = new CncNodeViewModel(node, (_, __) => { }); // Act & Assert Assert.Equal(expectedPath, vm.ManualImagePath); } [Fact] public void ManualImagePath_Set_UpdatesUnderlyingModel() { // Arrange var node = new SavePositionNode(Guid.NewGuid(), 0, "Pos_0", MotionState.Default); var vm = new CncNodeViewModel(node, (_, __) => { }); var newPath = @"C:\Images\updated.tiff"; // Act vm.ManualImagePath = newPath; // Assert var updatedNode = Assert.IsType(vm.Model); Assert.Equal(newPath, updatedNode.ManualImagePath); } #endregion } }