fix: restore test build and govern async callbacks

This commit is contained in:
zhengxuan.zhang
2026-08-10 14:13:32 +08:00
parent 5cacd4ddd7
commit 8e659a2474
18 changed files with 66 additions and 38 deletions
+2 -3
View File
@@ -1,3 +1,2 @@
global using XplorePlane.Services.ImageProcessing;
global using XplorePlane.Services.Logging;
global using XplorePlane.Services.Pipeline;
global using XplorePlane.Services.ImageProcessing;
global using XplorePlane.Services.Pipeline;
@@ -32,7 +32,7 @@ namespace XplorePlane.Tests.Inspection
Assert.Equal("Detector", result.Source);
Assert.Equal(2, result.Image.PixelWidth);
harness.Motion.Verify(x => x.MoveAllToTarget(It.IsAny<Dictionary<AxisId, double>>()), Times.Once);
harness.Motion.Verify(x => x.MoveAllToTarget(It.IsAny<Dictionary<AxisId, double>>(), false), Times.Once);
harness.Detector.Verify(x => x.ApplyParametersAsync(0, 1, 10m, 2, It.IsAny<CancellationToken>()), Times.Once);
harness.Detector.Verify(x => x.AcquireSingleFrameAsync(It.IsAny<CancellationToken>()), Times.Once);
harness.Ray.Verify(x => x.SetVoltage(120), Times.Once);
@@ -70,7 +70,7 @@ namespace XplorePlane.Tests.Inspection
harness.Service.AcquireAsync(Machine(), Acquisition(), CancellationToken.None));
Assert.Contains("安全门", error.Message);
harness.Motion.Verify(x => x.MoveAllToTarget(It.IsAny<Dictionary<AxisId, double>>()), Times.Never);
harness.Motion.Verify(x => x.MoveAllToTarget(It.IsAny<Dictionary<AxisId, double>>(), false), Times.Never);
harness.Ray.Verify(x => x.TurnOn(), Times.Never);
harness.Motion.Verify(x => x.StopAll(), Times.Once);
}
@@ -84,7 +84,7 @@ namespace XplorePlane.Tests.Inspection
harness.Service.AcquireAsync(Machine(), Acquisition(), CancellationToken.None));
Assert.Contains("探测器未连接", error.Message);
harness.Motion.Verify(x => x.MoveAllToTarget(It.IsAny<Dictionary<AxisId, double>>()), Times.Never);
harness.Motion.Verify(x => x.MoveAllToTarget(It.IsAny<Dictionary<AxisId, double>>(), false), Times.Never);
harness.Ray.Verify(x => x.TurnOn(), Times.Never);
}
@@ -113,7 +113,7 @@ namespace XplorePlane.Tests.Inspection
bool detectorConnected = true)
{
var motion = new Mock<IMotionControlService>();
motion.Setup(x => x.MoveAllToTarget(It.IsAny<Dictionary<AxisId, double>>()))
motion.Setup(x => x.MoveAllToTarget(It.IsAny<Dictionary<AxisId, double>>(), false))
.Returns(MotionResult.Ok());
motion.Setup(x => x.MoveRotaryToTarget(It.IsAny<RotaryAxisId>(), It.IsAny<double>(), It.IsAny<double?>()))
.Returns(MotionResult.Ok());
@@ -7,7 +7,7 @@ using XP.Common.Logging.Interfaces;
using XplorePlane.Models;
using XplorePlane.Services;
using XplorePlane.Services.Storage;
using XplorePlane.Services.Dialogs;
using XplorePlane.Views.Dialogs;
using XplorePlane.Tests.Helpers;
using XplorePlane.ViewModels;
using Xunit;
@@ -14,7 +14,7 @@ using XplorePlane.Models;
using XplorePlane.Services;
using XplorePlane.Services.Security;
using XplorePlane.Services.Storage;
using XplorePlane.Services.Dialogs;
using XplorePlane.Views.Dialogs;
using XplorePlane.Tests.Helpers;
using XplorePlane.ViewModels;
@@ -1,5 +1,5 @@
using System.Linq;
using XplorePlane.Services.Diagnostics;
using XplorePlane.Services.Helpers;
using Xunit;
namespace XplorePlane.Tests.Services
@@ -168,7 +168,7 @@ namespace XplorePlane.Tests.Services.Reporting
new JsonTemplateEngine(Logger().Object),
new ExpressionDataBinder(Logger().Object, loc.Object),
new PageLayoutEngine(Logger().Object, new JsonTemplateEngine(Logger().Object)),
new ITextPdfRenderer(Logger().Object, loc.Object));
new ITextPdfRenderer(Logger().Object, loc.Object, new XP.ReportEngine.Configs.ReportConfig()));
var outputPath = Path.Combine(Path.GetTempPath(), $"cnc_report_test_{Guid.NewGuid():N}.pdf");
@@ -16,7 +16,7 @@ using XP.Common.Logging.Interfaces;
using XplorePlane.Models;
using XplorePlane.Services.AppState;
using XplorePlane.Services.Cnc;
using XplorePlane.Services.Dialogs;
using XplorePlane.Views.Dialogs;
using XplorePlane.Services.Storage;
using XplorePlane.Services;
using XplorePlane.Services.Security;
@@ -10,7 +10,7 @@ using Xunit;
using XplorePlane.Models;
using XplorePlane.Services.Cnc;
using XplorePlane.Services.Cnc.Matrix;
using XplorePlane.Services.Dialogs;
using XplorePlane.Views.Dialogs;
using XplorePlane.ViewModels.Cnc;
namespace XplorePlane.Tests.ViewModels
@@ -224,7 +224,7 @@ namespace XplorePlane.Services.Hardware.Camera
app?.Dispatcher.BeginInvoke(() => FrameArrived?.Invoke(this, bitmap));
// 链式触发下一帧
TriggerNextLiveViewFrameAsync();
_ = TriggerNextLiveViewFrameAsync();
}
catch (Exception ex)
{
@@ -237,7 +237,7 @@ namespace XplorePlane.Services.Hardware.Camera
_logger.Warn($"相机采集错误: ErrorCode={e.ErrorCode}, {e.ErrorDescription}");
}
private async void TriggerNextLiveViewFrameAsync()
private async Task TriggerNextLiveViewFrameAsync()
{
if (!_liveViewRunning || _disposed)
return;
@@ -284,4 +284,4 @@ namespace XplorePlane.Services.Hardware.Camera
_logger.Info("CameraService 已释放");
}
}
}
}
@@ -0,0 +1,20 @@
using System;
using System.Text.Json;
using XplorePlane.Models.Inspection;
namespace XplorePlane.Services.Inspection
{
/// <summary>
/// 检测定义快照工具。用于在执行前冻结包含可变 PipelineModel 的定义,避免后续编辑影响运行快照。
/// </summary>
public static class InspectionDefinitionSnapshot
{
public static InspectionDefinition Clone(InspectionDefinition source)
{
ArgumentNullException.ThrowIfNull(source);
var json = JsonSerializer.Serialize(source);
return JsonSerializer.Deserialize<InspectionDefinition>(json)
?? throw new InvalidOperationException("无法创建检测定义快照。");
}
}
}
@@ -32,9 +32,10 @@ namespace XplorePlane.Services.Reporting
/// <summary>
/// CNC 报告上下文构建器实现 | CNC report context builder implementation
/// </summary>
public sealed class CncReportContextBuilder : ICncReportContextBuilder
{
private const string PassText = "PASS";
public sealed class CncReportContextBuilder : ICncReportContextBuilder
{
public const string CncTemplateRelativePath = @"Templates\CncInspectionReportTemplate.json";
private const string PassText = "PASS";
private const string FailText = "FAIL";
private const string EmptyText = "-";
@@ -595,4 +596,4 @@ namespace XplorePlane.Services.Reporting
#endregion | Private helpers
}
}
}
@@ -201,6 +201,9 @@ namespace XplorePlane.ViewModels.Cnc
}
private async void OnManualImageLoaded(ManualImageLoadedPayload payload)
=> await OnManualImageLoadedAsync(payload);
private async Task OnManualImageLoadedAsync(ManualImageLoadedPayload payload)
{
if (payload?.Image == null || _currentProgram == null || IsRunning)
return;
@@ -4,6 +4,7 @@
using Prism.Commands;
using Prism.Mvvm;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
@@ -51,7 +52,7 @@ namespace XplorePlane.ViewModels.ImageProcessing
AvailableProcessors.Add(new ProcessorItem(key, _imageProcessingService.GetProcessorDisplayName(key)));
SelectProcessorCommand = new DelegateCommand<string>(OnSelectProcessor);
ApplyProcessingCommand = new DelegateCommand(OnApplyProcessing);
ApplyProcessingCommand = new DelegateCommand(async () => await OnApplyProcessingAsync());
ResetImageCommand = new DelegateCommand(OnResetImage);
LoadImageCommand = new DelegateCommand(OnLoadImage);
SaveResultCommand = new DelegateCommand(OnSaveResult, () => CurrentImage != null);
@@ -131,7 +132,7 @@ namespace XplorePlane.ViewModels.ImageProcessing
}
}
private async void OnApplyProcessing()
private async Task OnApplyProcessingAsync()
{
if (CurrentImage == null || string.IsNullOrEmpty(SelectedProcessor)) return;
@@ -240,4 +241,4 @@ namespace XplorePlane.ViewModels.ImageProcessing
}
}
}
}
}
@@ -74,7 +74,7 @@ public class TemplateMatchBatchViewModel : BindableBase, IDisposable
_assistant.PropertyChanged += OnAssistantPropertyChanged;
PickFolderCommand = new DelegateCommand(ExecutePickFolder);
StartBatchCommand = new DelegateCommand(ExecuteStartBatch, CanStartBatch);
StartBatchCommand = new DelegateCommand(async () => await ExecuteStartBatchAsync(), CanStartBatch);
StopBatchCommand = new DelegateCommand(ExecuteStopBatch, () => _isRunning);
OpenSelectedInMainViewportCommand = new DelegateCommand(ExecuteOpenSelectedInMainViewport, () => SelectedRow != null);
}
@@ -180,7 +180,7 @@ public class TemplateMatchBatchViewModel : BindableBase, IDisposable
StartBatchCommand.RaiseCanExecuteChanged();
}
private async void ExecuteStartBatch()
private async Task ExecuteStartBatchAsync()
{
if (!CanStartBatch()) return;
@@ -347,4 +347,4 @@ public class TemplateMatchBatchViewModel : BindableBase, IDisposable
_batchCts?.Dispose();
_batchCts = null;
}
}
}
@@ -53,7 +53,7 @@ namespace XplorePlane.ViewModels.Main
#region CNC
private async void ExecuteCncEditorAction(Action<CncEditorViewModel> action)
private void ExecuteCncEditorAction(Action<CncEditorViewModel> action)
{
ArgumentNullException.ThrowIfNull(action);
try
@@ -116,6 +116,9 @@ namespace XplorePlane.ViewModels.Main
/// <summary>响应"把实时流水线作为检测模块加入 CNC"请求。</summary>
private async void OnAddPipelineToCncRequested(XplorePlane.Models.ImageProcessing.PipelineModel pipeline)
=> await OnAddPipelineToCncRequestedAsync(pipeline);
private async Task OnAddPipelineToCncRequestedAsync(XplorePlane.Models.ImageProcessing.PipelineModel pipeline)
{
try
{
@@ -181,4 +184,4 @@ namespace XplorePlane.ViewModels.Main
#endregion
}
}
}
+9 -8
View File
@@ -3,6 +3,7 @@ using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
@@ -733,7 +734,7 @@ namespace XplorePlane.ViewModels.Main
OpenOverlaySettingsCommand = new DelegateCommand(ExecuteOpenOverlaySettings);
OpenLibraryVersionsCommand = new DelegateCommand(() => _windowLauncher.Show(new Views.Help.LibraryVersionsWindow(), "关于"));
OpenUserManualCommand = new DelegateCommand(ExecuteOpenUserManual);
CheckForUpdateCommand = new DelegateCommand(ExecuteCheckForUpdate);
CheckForUpdateCommand = new DelegateCommand(async () => await ExecuteCheckForUpdateAsync());
OpenCameraSettingsCommand = new DelegateCommand(ExecuteOpenCameraSettings);
OpenCameraChessboardCalibrationCommand = new DelegateCommand(ExecuteOpenCameraChessboardCalibration);
OpenCameraCalibrationCommand = new DelegateCommand(ExecuteOpenCameraCalibration);
@@ -798,8 +799,8 @@ namespace XplorePlane.ViewModels.Main
BlackBackgroundDetectionCommand = new DelegateCommand(ExecuteBlackBackgroundDetection);
OpenTemplateMatchAssistantCommand = new DelegateCommand(ExecuteOpenTemplateMatchAssistant);
GrayscaleCommand = new DelegateCommand(ExecuteGrayscale);
SharpenCommand = new DelegateCommand(ExecuteSharpen);
EnhanceCommand = new DelegateCommand(ExecuteEnhance);
SharpenCommand = new DelegateCommand(async () => await ExecuteSharpenAsync());
EnhanceCommand = new DelegateCommand(async () => await ExecuteEnhanceAsync());
EdgeLineFitCommand = new DelegateCommand(ExecuteEdgeLineFit);
EdgeCircleFitCommand = new DelegateCommand(ExecuteEdgeCircleFit);
@@ -810,7 +811,7 @@ namespace XplorePlane.ViewModels.Main
OpenMotionDebugCommand = new DelegateCommand(ExecuteOpenMotionDebug);
RandomMoveAxesCommand = new DelegateCommand(ExecuteRandomMoveAxes);
OpenCalibrationWizardCommand = new DelegateCommand(ExecuteOpenCalibrationWizard);
OneClickInitializeCommand = new DelegateCommand(ExecuteOneClickInitialize);
OneClickInitializeCommand = new DelegateCommand(async () => await ExecuteOneClickInitializeAsync());
OpenPlcAddrConfigCommand = new DelegateCommand(ExecuteOpenPlcAddrConfig);
OpenRaySourceConfigCommand = new DelegateCommand(ExecuteOpenRaySourceConfig);
OpenReportConfigCommand = new DelegateCommand(ExecuteOpenReportConfig);
@@ -957,7 +958,7 @@ namespace XplorePlane.ViewModels.Main
}
}
private async void ExecuteCheckForUpdate()
private async Task ExecuteCheckForUpdateAsync()
{
try
{
@@ -1289,7 +1290,7 @@ namespace XplorePlane.ViewModels.Main
throw new InvalidOperationException("导航相机有效视野与 StageX/StageY 轴行程没有可用交集。");
}
private async void ExecuteOneClickInitialize()
private async Task ExecuteOneClickInitializeAsync()
{
try
{
@@ -1468,7 +1469,7 @@ namespace XplorePlane.ViewModels.Main
}
}
private async void ExecuteSharpen()
private async Task ExecuteSharpenAsync()
{
if (!CheckImageLoaded()) return;
@@ -1503,7 +1504,7 @@ namespace XplorePlane.ViewModels.Main
}
}
private async void ExecuteEnhance()
private async Task ExecuteEnhanceAsync()
{
if (!CheckImageLoaded()) return;
@@ -479,7 +479,7 @@ namespace XplorePlane.ViewModels.Main
/// </summary>
/// <param name="pixelX">图像像素 X</param>
/// <param name="pixelY">图像像素 Y</param>
public async void NavigateToPixel(double pixelX, double pixelY)
public async Task NavigateToPixel(double pixelX, double pixelY)
{
if (!IsCalibrated)
{
@@ -387,7 +387,7 @@ namespace XplorePlane.Views.Main
return;
}
_viewModel.NavigateToPixel(px, py);
_ = _viewModel.NavigateToPixel(px, py);
}
#region PiP (Picture-in-Picture) -