279 lines
9.7 KiB
C#
279 lines
9.7 KiB
C#
using Moq;
|
|
using XP.Common.Logging.Interfaces;
|
|
using XplorePlane.Models;
|
|
using XplorePlane.Services;
|
|
using XplorePlane.Tests.Helpers;
|
|
using XplorePlane.ViewModels;
|
|
using Xunit;
|
|
|
|
namespace XplorePlane.Tests.Pipeline
|
|
{
|
|
/// <summary>
|
|
/// 测试 PipelineEditorViewModel 的命令逻辑
|
|
/// 覆盖任务 6.1 / 6.2 / 6.3 / 6.4 / 6.8
|
|
/// </summary>
|
|
public class PipelineEditorViewModelTests
|
|
{
|
|
private readonly Mock<IImageProcessingService> _mockImageSvc;
|
|
private readonly Mock<IPipelineExecutionService> _mockExecSvc;
|
|
private readonly Mock<IPipelinePersistenceService> _mockPersistSvc;
|
|
private readonly Mock<ILoggerService> _mockLogger;
|
|
|
|
public PipelineEditorViewModelTests()
|
|
{
|
|
_mockImageSvc = TestHelpers.CreateMockImageService();
|
|
_mockExecSvc = new Mock<IPipelineExecutionService>();
|
|
_mockPersistSvc = new Mock<IPipelinePersistenceService>();
|
|
_mockLogger = new Mock<ILoggerService>();
|
|
_mockLogger.Setup(l => l.ForModule<PipelineEditorViewModel>()).Returns(_mockLogger.Object);
|
|
}
|
|
|
|
private PipelineEditorViewModel CreateVm() =>
|
|
new PipelineEditorViewModel(_mockImageSvc.Object, _mockExecSvc.Object, _mockPersistSvc.Object, _mockLogger.Object);
|
|
|
|
// ── 6.1 AddOperatorCommand ────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void AddOperator_ValidKey_AppendsNode()
|
|
{
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
|
|
Assert.Single(vm.PipelineNodes);
|
|
Assert.Equal("Blur", vm.PipelineNodes[0].OperatorKey);
|
|
Assert.Equal(0, vm.PipelineNodes[0].Order);
|
|
}
|
|
|
|
[Fact]
|
|
public void AddOperator_InvalidKey_NodeNotAdded()
|
|
{
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("NonExistentKey");
|
|
|
|
Assert.Empty(vm.PipelineNodes);
|
|
Assert.Contains("未注册", vm.StatusMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public void AddOperator_NullKey_NodeNotAdded()
|
|
{
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute(null);
|
|
|
|
Assert.Empty(vm.PipelineNodes);
|
|
}
|
|
|
|
[Fact]
|
|
public void AddOperator_ExceedsMaxLength_NodeNotAdded()
|
|
{
|
|
// 主项目中 MaxPipelineLength = 20,通过反射读取或直接添加 20 个
|
|
var vm = CreateVm();
|
|
for (int i = 0; i < 20; i++)
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
|
|
Assert.Equal(20, vm.PipelineNodes.Count);
|
|
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
|
|
Assert.Equal(20, vm.PipelineNodes.Count);
|
|
Assert.Contains("上限", vm.StatusMessage);
|
|
}
|
|
|
|
[Fact]
|
|
public void AddOperator_MultipleNodes_OrderIsSequential()
|
|
{
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
vm.AddOperatorCommand.Execute("Sharpen");
|
|
vm.AddOperatorCommand.Execute("Threshold");
|
|
|
|
Assert.Equal(3, vm.PipelineNodes.Count);
|
|
for (int i = 0; i < 3; i++)
|
|
Assert.Equal(i, vm.PipelineNodes[i].Order);
|
|
}
|
|
|
|
// ── 6.2 RemoveOperatorCommand ─────────────────────────────────
|
|
|
|
[Fact]
|
|
public void RemoveOperator_ExistingNode_NodeRemoved()
|
|
{
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
var node = vm.PipelineNodes[0];
|
|
|
|
vm.RemoveOperatorCommand.Execute(node);
|
|
|
|
Assert.Empty(vm.PipelineNodes);
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveOperator_MiddleNode_OrderRenumbered()
|
|
{
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
vm.AddOperatorCommand.Execute("Sharpen");
|
|
vm.AddOperatorCommand.Execute("Threshold");
|
|
var middle = vm.PipelineNodes[1];
|
|
|
|
vm.RemoveOperatorCommand.Execute(middle);
|
|
|
|
Assert.Equal(2, vm.PipelineNodes.Count);
|
|
Assert.Equal(0, vm.PipelineNodes[0].Order);
|
|
Assert.Equal(1, vm.PipelineNodes[1].Order);
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveOperator_SelectedNode_SelectedNodeCleared()
|
|
{
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
var node = vm.PipelineNodes[0];
|
|
vm.SelectedNode = node;
|
|
|
|
vm.RemoveOperatorCommand.Execute(node);
|
|
|
|
Assert.Null(vm.SelectedNode);
|
|
}
|
|
|
|
[Fact]
|
|
public void RemoveOperator_NullNode_NoException()
|
|
{
|
|
var vm = CreateVm();
|
|
var ex = Record.Exception(() => vm.RemoveOperatorCommand.Execute(null));
|
|
Assert.Null(ex);
|
|
}
|
|
|
|
// ── 6.3 ReorderOperatorCommand ────────────────────────────────
|
|
|
|
[Fact]
|
|
public void ReorderOperator_MoveFirstToLast_OrderConsistent()
|
|
{
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
vm.AddOperatorCommand.Execute("Sharpen");
|
|
vm.AddOperatorCommand.Execute("Threshold");
|
|
|
|
vm.ReorderOperatorCommand.Execute(new PipelineReorderArgs { OldIndex = 0, NewIndex = 2 });
|
|
|
|
for (int i = 0; i < vm.PipelineNodes.Count; i++)
|
|
Assert.Equal(i, vm.PipelineNodes[i].Order);
|
|
}
|
|
|
|
[Fact]
|
|
public void ReorderOperator_MoveLastToFirst_OrderConsistent()
|
|
{
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
vm.AddOperatorCommand.Execute("Sharpen");
|
|
vm.AddOperatorCommand.Execute("Threshold");
|
|
var lastName = vm.PipelineNodes[2].OperatorKey;
|
|
|
|
vm.ReorderOperatorCommand.Execute(new PipelineReorderArgs { OldIndex = 2, NewIndex = 0 });
|
|
|
|
Assert.Equal(lastName, vm.PipelineNodes[0].OperatorKey);
|
|
for (int i = 0; i < vm.PipelineNodes.Count; i++)
|
|
Assert.Equal(i, vm.PipelineNodes[i].Order);
|
|
}
|
|
|
|
[Fact]
|
|
public void ReorderOperator_SameIndex_NoChange()
|
|
{
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
vm.AddOperatorCommand.Execute("Sharpen");
|
|
var originalFirst = vm.PipelineNodes[0].OperatorKey;
|
|
|
|
vm.ReorderOperatorCommand.Execute(new PipelineReorderArgs { OldIndex = 0, NewIndex = 0 });
|
|
|
|
Assert.Equal(originalFirst, vm.PipelineNodes[0].OperatorKey);
|
|
}
|
|
|
|
[Fact]
|
|
public void ReorderOperator_OutOfBoundsIndex_NoException()
|
|
{
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
|
|
var ex = Record.Exception(() =>
|
|
vm.ReorderOperatorCommand.Execute(new PipelineReorderArgs { OldIndex = 0, NewIndex = 99 }));
|
|
Assert.Null(ex);
|
|
}
|
|
|
|
// ── 6.4 LoadNodeParameters ────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void LoadNodeParameters_ModifiedValuePreserved()
|
|
{
|
|
var param = TestHelpers.MakeIntParam("Radius", value: 5, min: 1, max: 20);
|
|
_mockImageSvc.Setup(s => s.GetProcessorParameters("Blur"))
|
|
.Returns(new[] { param });
|
|
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
var node = vm.PipelineNodes[0];
|
|
|
|
// 修改参数值
|
|
node.Parameters[0].Value = 10;
|
|
|
|
// 重新选中节点触发 LoadNodeParameters
|
|
vm.SelectedNode = null;
|
|
vm.SelectedNode = node;
|
|
|
|
Assert.Equal(10, node.Parameters[0].Value);
|
|
}
|
|
|
|
[Fact]
|
|
public void LoadNodeParameters_UnmodifiedUsesDefault()
|
|
{
|
|
var param = TestHelpers.MakeIntParam("Radius", value: 5, min: 1, max: 20);
|
|
_mockImageSvc.Setup(s => s.GetProcessorParameters("Blur"))
|
|
.Returns(new[] { param });
|
|
|
|
var vm = CreateVm();
|
|
vm.AddOperatorCommand.Execute("Blur");
|
|
var node = vm.PipelineNodes[0];
|
|
|
|
Assert.Equal(5, node.Parameters[0].Value);
|
|
}
|
|
|
|
// ── 6.8 参数范围校验 ──────────────────────────────────────────
|
|
|
|
[Fact]
|
|
public void ParameterValidation_ValueWithinRange_IsValid()
|
|
{
|
|
var param = TestHelpers.MakeIntParam("Radius", value: 5, min: 1, max: 10);
|
|
var vm = new ProcessorParameterVM(param) { Value = 7 };
|
|
|
|
Assert.True(vm.IsValueValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParameterValidation_ValueBelowMin_IsInvalid()
|
|
{
|
|
var param = TestHelpers.MakeIntParam("Radius", value: 5, min: 1, max: 10);
|
|
var vm = new ProcessorParameterVM(param) { Value = 0 };
|
|
|
|
Assert.False(vm.IsValueValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParameterValidation_ValueAboveMax_IsInvalid()
|
|
{
|
|
var param = TestHelpers.MakeIntParam("Radius", value: 5, min: 1, max: 10);
|
|
var vm = new ProcessorParameterVM(param) { Value = 11 };
|
|
|
|
Assert.False(vm.IsValueValid);
|
|
}
|
|
|
|
[Fact]
|
|
public void ParameterValidation_BoundaryValues_AreValid()
|
|
{
|
|
var param = TestHelpers.MakeIntParam("Radius", value: 5, min: 1, max: 10);
|
|
var vmMin = new ProcessorParameterVM(param) { Value = 1 };
|
|
var vmMax = new ProcessorParameterVM(param) { Value = 10 };
|
|
|
|
Assert.True(vmMin.IsValueValid);
|
|
Assert.True(vmMax.IsValueValid);
|
|
}
|
|
}
|
|
} |