下拉检测模块列表
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// Feature: cnc-run-execution
|
||||
// Feature: cnc-run-execution
|
||||
// Properties 1, 2, 12: CncEditorViewModel execution control
|
||||
|
||||
using System;
|
||||
@@ -17,6 +17,7 @@ using XplorePlane.Models;
|
||||
using XplorePlane.Services.AppState;
|
||||
using XplorePlane.Services.Cnc;
|
||||
using XplorePlane.Services.Storage;
|
||||
using XplorePlane.Services;
|
||||
using XplorePlane.ViewModels.Cnc;
|
||||
using Xunit;
|
||||
|
||||
@@ -24,16 +25,18 @@ namespace XplorePlane.Tests.ViewModels
|
||||
{
|
||||
public class CncEditorViewModelTests
|
||||
{
|
||||
// ── Helpers ──────────────────────────────────────────────────────────
|
||||
// 鈹€鈹€ Helpers 鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
||||
|
||||
private static CncEditorViewModel CreateVm(
|
||||
Mock<ICncExecutionService> mockExecSvc = null,
|
||||
CncProgram initialProgram = null)
|
||||
CncProgram initialProgram = null,
|
||||
Mock<IPipelinePersistenceService> mockPipelinePersistenceService = null)
|
||||
{
|
||||
var mockCncProgramSvc = new Mock<ICncProgramService>();
|
||||
var mockAppState = new Mock<IAppStateService>();
|
||||
var mockLogger = new Mock<ILoggerService>();
|
||||
var mockDataPathService = new Mock<IXpDataPathService>();
|
||||
mockPipelinePersistenceService ??= new Mock<IPipelinePersistenceService>();
|
||||
mockLogger.Setup(l => l.ForModule<CncEditorViewModel>()).Returns(mockLogger.Object);
|
||||
mockDataPathService.SetupGet(s => s.PlanPath).Returns(System.IO.Path.GetTempPath());
|
||||
|
||||
@@ -47,16 +50,52 @@ namespace XplorePlane.Tests.ViewModels
|
||||
DateTime.UtcNow, DateTime.UtcNow,
|
||||
new List<CncNode>
|
||||
{
|
||||
new ReferencePointNode(Guid.NewGuid(), 0, "参考点_0", 0, 0, 0, 0, 0, 0, false, 0, 0)
|
||||
new ReferencePointNode(Guid.NewGuid(), 0, "鍙傝€冪偣_0", 0, 0, 0, 0, 0, 0, false, 0, 0)
|
||||
}.AsReadOnly()));
|
||||
|
||||
mockCncProgramSvc
|
||||
.Setup(s => s.CreateNode(It.IsAny<CncNodeType>()))
|
||||
.Returns((CncNodeType nodeType) => nodeType switch
|
||||
{
|
||||
CncNodeType.InspectionModule => new InspectionModuleNode(Guid.NewGuid(), 0, "检测模块_0", new PipelineModel()),
|
||||
CncNodeType.ReferencePoint => new ReferencePointNode(Guid.NewGuid(), 0, "参考点_0", 0, 0, 0, 0, 0, 0, false, 0, 0),
|
||||
_ => throw new InvalidOperationException($"Unsupported node type in test: {nodeType}")
|
||||
});
|
||||
|
||||
mockCncProgramSvc
|
||||
.Setup(s => s.InsertNode(It.IsAny<CncProgram>(), It.IsAny<int>(), It.IsAny<CncNode>()))
|
||||
.Returns((CncProgram program, int afterIndex, CncNode node) =>
|
||||
{
|
||||
var nodes = program.Nodes.ToList();
|
||||
var insertIndex = Math.Clamp(afterIndex + 1, 0, nodes.Count);
|
||||
nodes.Insert(insertIndex, node with { Index = insertIndex });
|
||||
|
||||
for (var i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
nodes[i] = nodes[i] with { Index = i };
|
||||
}
|
||||
|
||||
return program with { Nodes = nodes.AsReadOnly(), UpdatedAt = DateTime.UtcNow };
|
||||
});
|
||||
|
||||
mockCncProgramSvc
|
||||
.Setup(s => s.UpdateNode(It.IsAny<CncProgram>(), It.IsAny<int>(), It.IsAny<CncNode>()))
|
||||
.Returns((CncProgram program, int index, CncNode updatedNode) =>
|
||||
{
|
||||
var nodes = program.Nodes.ToList();
|
||||
nodes[index] = updatedNode with { Index = index };
|
||||
return program with { Nodes = nodes.AsReadOnly(), UpdatedAt = DateTime.UtcNow };
|
||||
});
|
||||
|
||||
|
||||
var vm = new CncEditorViewModel(
|
||||
mockCncProgramSvc.Object,
|
||||
mockAppState.Object,
|
||||
new EventAggregator(),
|
||||
mockLogger.Object,
|
||||
mockExecSvc.Object,
|
||||
mockDataPathService.Object);
|
||||
mockDataPathService.Object,
|
||||
mockPipelinePersistenceService.Object);
|
||||
|
||||
if (initialProgram != null)
|
||||
{
|
||||
@@ -82,9 +121,9 @@ namespace XplorePlane.Tests.ViewModels
|
||||
return new CncProgram(Guid.NewGuid(), "TestProgram", DateTime.UtcNow, DateTime.UtcNow, nodes);
|
||||
}
|
||||
|
||||
// ── Property 1: 运行/停止按钮状态互斥 ────────────────────────────────
|
||||
// 鈹€鈹€ Property 1: 杩愯/鍋滄鎸夐挳鐘舵€佷簰鏂?鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
||||
|
||||
// Feature: cnc-run-execution, Property 1: 运行/停止按钮状态互斥
|
||||
// Feature: cnc-run-execution, Property 1: 杩愯/鍋滄鎸夐挳鐘舵€佷簰鏂?
|
||||
// Validates: Requirements 1.1, 1.3, 1.4
|
||||
[Property(MaxTest = 100)]
|
||||
public Property RunStop_Commands_AreMutuallyExclusive()
|
||||
@@ -129,9 +168,9 @@ namespace XplorePlane.Tests.ViewModels
|
||||
});
|
||||
}
|
||||
|
||||
// ── Property 2: 执行完成后状态重置 ───────────────────────────────────
|
||||
// 鈹€鈹€ Property 2: 鎵ц瀹屾垚鍚庣姸鎬侀噸缃?鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
||||
|
||||
// Feature: cnc-run-execution, Property 2: 执行完成后状态重置
|
||||
// Feature: cnc-run-execution, Property 2: 鎵ц瀹屾垚鍚庣姸鎬侀噸缃?
|
||||
// Validates: Requirements 1.7, 6.5
|
||||
[Property(MaxTest = 100)]
|
||||
public Property AfterExecution_IsRunningFalse_AllNodesIdle()
|
||||
@@ -180,9 +219,9 @@ namespace XplorePlane.Tests.ViewModels
|
||||
});
|
||||
}
|
||||
|
||||
// ── Property 12: 执行中编辑命令全部禁用 ──────────────────────────────
|
||||
// 鈹€鈹€ Property 12: 鎵ц涓紪杈戝懡浠ゅ叏閮ㄧ鐢?鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€鈹€
|
||||
|
||||
// Feature: cnc-run-execution, Property 12: 执行中编辑命令全部禁用
|
||||
// Feature: cnc-run-execution, Property 12: 鎵ц涓紪杈戝懡浠ゅ叏閮ㄧ鐢?
|
||||
// Validates: Requirements 6.7
|
||||
[Property(MaxTest = 100)]
|
||||
public Property WhileRunning_AllEditCommands_AreDisabled()
|
||||
@@ -232,5 +271,50 @@ namespace XplorePlane.Tests.ViewModels
|
||||
return allDisabled;
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task InsertInspectionModuleFromPipelineFileAsync_LoadsPipelineAndInsertsNode()
|
||||
{
|
||||
var pipelineFile = System.IO.Path.Combine(System.IO.Path.GetTempPath(), $"{Guid.NewGuid():N}.xpm");
|
||||
await System.IO.File.WriteAllTextAsync(pipelineFile, "{}");
|
||||
|
||||
try
|
||||
{
|
||||
var expectedPipeline = new PipelineModel
|
||||
{
|
||||
Name = "BuiltIn/ModuleA"
|
||||
};
|
||||
|
||||
var mockPipelinePersistenceService = new Mock<IPipelinePersistenceService>();
|
||||
mockPipelinePersistenceService
|
||||
.Setup(s => s.LoadAsync(pipelineFile))
|
||||
.ReturnsAsync(expectedPipeline);
|
||||
|
||||
var initialProgram = new CncProgram(
|
||||
Guid.NewGuid(),
|
||||
"TestProgram",
|
||||
DateTime.UtcNow,
|
||||
DateTime.UtcNow,
|
||||
new List<CncNode>
|
||||
{
|
||||
new SavePositionNode(Guid.NewGuid(), 0, "保存位置_0", MotionState.Default)
|
||||
}.AsReadOnly());
|
||||
|
||||
var vm = CreateVm(
|
||||
initialProgram: initialProgram,
|
||||
mockPipelinePersistenceService: mockPipelinePersistenceService);
|
||||
|
||||
await vm.InsertInspectionModuleFromPipelineFileAsync(pipelineFile);
|
||||
|
||||
var insertedNode = Assert.IsType<InspectionModuleNode>(vm.Nodes.Last().Model);
|
||||
Assert.Same(expectedPipeline, insertedNode.Pipeline);
|
||||
Assert.Equal("BuiltIn/ModuleA", insertedNode.Pipeline.Name);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (System.IO.File.Exists(pipelineFile))
|
||||
System.IO.File.Delete(pipelineFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user