主视口没有可用图像时,回退到 IAppStateService.LatestDetectorFrame
This commit is contained in:
@@ -3,14 +3,18 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using FsCheck;
|
||||
using FsCheck.Fluent;
|
||||
using FsCheck.Xunit;
|
||||
using Moq;
|
||||
using XP.Common.Logging.Interfaces;
|
||||
using XP.Hardware.Detector.Abstractions;
|
||||
using XplorePlane.Models;
|
||||
using XplorePlane.Services.Cnc;
|
||||
using XplorePlane.Services;
|
||||
using XplorePlane.Services.AppState;
|
||||
using XplorePlane.Services.InspectionResults;
|
||||
using XplorePlane.Services.MainViewport;
|
||||
using Xunit;
|
||||
@@ -172,12 +176,13 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
|
||||
public class CncExecutionServiceTests
|
||||
{
|
||||
private static (CncExecutionService Service, Mock<IInspectionResultStore> Store, Mock<ILoggerService> Logger)
|
||||
private static (CncExecutionService Service, Mock<IInspectionResultStore> Store, Mock<ILoggerService> Logger, Mock<IMainViewportService> MainViewport, Mock<IAppStateService> AppState)
|
||||
CreateService()
|
||||
{
|
||||
var mockStore = new Mock<IInspectionResultStore>();
|
||||
var mockLogger = new Mock<ILoggerService>();
|
||||
var mockMainViewportService = new Mock<IMainViewportService>();
|
||||
var mockAppStateService = new Mock<IAppStateService>();
|
||||
var mockPipelineExecutionService = new Mock<IPipelineExecutionService>();
|
||||
var mockImageProcessingService = new Mock<IImageProcessingService>();
|
||||
mockLogger.Setup(l => l.ForModule<CncExecutionService>()).Returns(mockLogger.Object);
|
||||
@@ -204,9 +209,10 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
mockStore.Object,
|
||||
mockLogger.Object,
|
||||
mockMainViewportService.Object,
|
||||
mockAppStateService.Object,
|
||||
mockPipelineExecutionService.Object,
|
||||
mockImageProcessingService.Object);
|
||||
return (service, mockStore, mockLogger);
|
||||
return (service, mockStore, mockLogger, mockMainViewportService, mockAppStateService);
|
||||
}
|
||||
|
||||
// ── Property 3: 预取消立即返回 ────────────────────────────────────────
|
||||
@@ -220,7 +226,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
CncProgramGenerators.CncProgramArb(1, 10),
|
||||
program =>
|
||||
{
|
||||
var (service, mockStore, _) = CreateService();
|
||||
var (service, mockStore, _, _, _) = CreateService();
|
||||
|
||||
using var cts = new CancellationTokenSource();
|
||||
cts.Cancel();
|
||||
@@ -247,7 +253,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
CncProgramGenerators.CncProgramArb(2, 8),
|
||||
program =>
|
||||
{
|
||||
var (service, _, _) = CreateService();
|
||||
var (service, _, _, _, _) = CreateService();
|
||||
|
||||
var runningReports = new List<Guid>();
|
||||
// Use SynchronousProgress to avoid async callback timing issues
|
||||
@@ -304,7 +310,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
gen.ToArbitrary(),
|
||||
program =>
|
||||
{
|
||||
var (service, _, _) = CreateService();
|
||||
var (service, _, _, _, _) = CreateService();
|
||||
|
||||
var runningIds = new List<Guid>();
|
||||
var progress = new SynchronousProgress<CncNodeExecutionProgress>(p =>
|
||||
@@ -355,7 +361,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
CncProgramGenerators.CncProgramArb(1, 8),
|
||||
program =>
|
||||
{
|
||||
var (service, mockStore, _) = CreateService();
|
||||
var (service, mockStore, _, _, _) = CreateService();
|
||||
|
||||
InspectionRunRecord capturedRecord = null;
|
||||
mockStore.Setup(s => s.BeginRunAsync(
|
||||
@@ -386,7 +392,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
CncProgramGenerators.CncProgramArb(1, 10),
|
||||
program =>
|
||||
{
|
||||
var (service, mockStore, _) = CreateService();
|
||||
var (service, mockStore, _, _, _) = CreateService();
|
||||
|
||||
service.ExecuteAsync(program, null, CancellationToken.None)
|
||||
.GetAwaiter().GetResult();
|
||||
@@ -421,7 +427,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
CncProgramGenerators.CncProgramArb(1, 10),
|
||||
program =>
|
||||
{
|
||||
var (service, mockStore, _) = CreateService();
|
||||
var (service, mockStore, _, _, _) = CreateService();
|
||||
|
||||
InspectionRunRecord capturedRecord = null;
|
||||
mockStore.Setup(s => s.BeginRunAsync(
|
||||
@@ -449,7 +455,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
CncProgramGenerators.CncProgramArb(1, 8),
|
||||
program =>
|
||||
{
|
||||
var (service, mockStore, _) = CreateService();
|
||||
var (service, mockStore, _, _, _) = CreateService();
|
||||
|
||||
bool? capturedOverallPass = default;
|
||||
bool callbackInvoked = false;
|
||||
@@ -482,7 +488,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
// Validates: Requirements 4.4, 4.5
|
||||
public void CompleteRunAsync_CalledWithNullOverallPass_WhenCancelled()
|
||||
{
|
||||
var (service, mockStore, _) = CreateService();
|
||||
var (service, mockStore, _, _, _) = CreateService();
|
||||
|
||||
// Use a WaitDelayNode with long delay so cancellation happens during execution
|
||||
var waitNode = new WaitDelayNode(Guid.NewGuid(), 0, "LongWait", 5000);
|
||||
@@ -530,7 +536,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
CncProgramGenerators.CncProgramWithInspectionNodesArb(2),
|
||||
program =>
|
||||
{
|
||||
var (service, mockStore, _) = CreateService();
|
||||
var (service, mockStore, _, _, _) = CreateService();
|
||||
|
||||
// Make AppendNodeResultAsync always throw
|
||||
mockStore.Setup(s => s.AppendNodeResultAsync(
|
||||
@@ -587,7 +593,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
gen.ToArbitrary(),
|
||||
waitNode =>
|
||||
{
|
||||
var (service, mockStore, _) = CreateService();
|
||||
var (service, mockStore, _, _, _) = CreateService();
|
||||
|
||||
bool? capturedOverallPass = default;
|
||||
mockStore.Setup(s => s.CompleteRunAsync(
|
||||
@@ -630,7 +636,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
CncProgramGenerators.CncProgramArb(1, 8),
|
||||
program =>
|
||||
{
|
||||
var (service, _, _) = CreateService();
|
||||
var (service, _, _, _, _) = CreateService();
|
||||
|
||||
// Build a map of NodeId → CncNodeViewModel
|
||||
var nodeVms = program.Nodes
|
||||
@@ -700,7 +706,7 @@ internal sealed class SynchronousProgress<T> : IProgress<T>
|
||||
tuple =>
|
||||
{
|
||||
var (program, node, expectedPipelineName) = tuple;
|
||||
var (service, mockStore, _) = CreateService();
|
||||
var (service, mockStore, _, _, _) = CreateService();
|
||||
|
||||
PipelineExecutionSnapshot capturedSnapshot = null;
|
||||
mockStore.Setup(s => s.AppendNodeResultAsync(
|
||||
|
||||
Reference in New Issue
Block a user