test: fix runtime test failures

This commit is contained in:
zhengxuan.zhang
2026-08-10 14:31:44 +08:00
parent 8e659a2474
commit f8fce8f13f
12 changed files with 112 additions and 51 deletions
@@ -0,0 +1,28 @@
{
"document": {
"pageSize": "A4",
"orientation": "Portrait",
"margins": { "top": 40, "bottom": 20, "left": 20, "right": 20 }
},
"pages": [
{
"type": "homepage",
"elements": [
{ "type": "text", "content": "${hpOverallLine}", "positioning": "flow" },
{ "type": "text", "content": "${hpProgramLine}", "positioning": "flow" },
{ "type": "text", "content": "${hpSampleLine}", "positioning": "flow" }
]
},
{
"type": "nodeDetail",
"repeat": "nodeSections",
"elements": [
{ "type": "text", "content": "${nodeHeading}", "positioning": "flow" },
{ "type": "text", "content": "${nodeInfoText}", "positioning": "flow" },
{ "type": "text", "content": "${nodeResultLine}", "positioning": "flow" },
{ "type": "table", "dataKey": "nodeMetricsTable", "positioning": "flow", "size": [170, 0], "columns": [] }
]
}
],
"styles": {}
}
@@ -41,7 +41,7 @@ namespace XplorePlane.Tests.Inspection
Assert.Equal(4, loaded.Geometry.BgaGrid.Rows);
Assert.Equal("BgaVoidRate", loaded.Analysis.AdvancedDetectorType);
var json = await File.ReadAllTextAsync(Path.Combine(_directory, $"{definition.Id:D}.json"));
var json = await File.ReadAllTextAsync(Path.Combine(_directory, $"{definition.Id:D}.xppool"));
Assert.Contains("焊球空洞检测", json);
Assert.DoesNotContain("\\u710a", json, StringComparison.OrdinalIgnoreCase);
}
@@ -86,17 +86,17 @@ namespace XplorePlane.Tests.Inspection
Assert.Equal(2, loadedImage.PixelWidth);
Assert.NotEqual(source.ReferenceImage.RelativePath, clone.ReferenceImage.RelativePath);
Assert.True(File.Exists(Path.Combine(_directory, clone.ReferenceImage.RelativePath)));
Assert.True(File.Exists(Path.Combine(_directory, clone.ReferenceImage.RelativePath)));
await _repository.DeleteAsync(clone.Id);
Assert.False(Directory.Exists(Path.Combine(_directory, "Assets", clone.Id.ToString("D"))));
Assert.False(Directory.Exists(Path.Combine(_directory, "References", clone.Id.ToString("D"))));
}
[Fact]
public async Task List_RemovesOrphanReferenceAssetDirectories()
{
var orphanId = Guid.NewGuid();
var orphanDirectory = Path.Combine(_directory, "Assets", orphanId.ToString("D"));
var orphanDirectory = Path.Combine(_directory, "References", orphanId.ToString("D"));
Directory.CreateDirectory(orphanDirectory);
await File.WriteAllTextAsync(Path.Combine(orphanDirectory, "reference.png"), "orphan");
@@ -28,8 +28,8 @@ namespace XplorePlane.Tests.Services
var config = service.Load();
Assert.Equal("Hikvision", config.CameraType);
Assert.Equal(string.Empty, config.CameraSimulatedImagePath);
Assert.Equal(CameraConfig.Default.CameraType, config.CameraType);
Assert.Equal(CameraConfig.Default.CameraSimulatedImagePath, config.CameraSimulatedImagePath);
}
[Fact]
+9 -4
View File
@@ -31,10 +31,15 @@
<Compile Remove="Services\ProgressReportPropertyTests.cs" />
</ItemGroup>
<ItemGroup>
<None Remove="Helpers\Define.cs.bak" />
</ItemGroup>
<ItemGroup>
<ItemGroup>
<None Remove="Helpers\Define.cs.bak" />
</ItemGroup>
<ItemGroup>
<None Include="..\XP.ReportEngine\Templates\CncInspectionReportTemplate.json" Link="Templates\CncInspectionReportTemplate.json" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.*" />
<PackageReference Include="xunit" Version="2.*" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.*" />
@@ -98,7 +98,7 @@ namespace XplorePlane.Services.Helpers
foreach (var assemblyName in descriptor.AssemblyNames)
{
var path = Path.Combine(AppContext.BaseDirectory, assemblyName + ".dll");
var path = FindDeployedAssemblyPath(assemblyName);
if (!File.Exists(path))
continue;
@@ -122,6 +122,37 @@ namespace XplorePlane.Services.Helpers
false);
}
private static string FindDeployedAssemblyPath(string assemblyName)
{
var fileName = assemblyName + ".dll";
var roots = new List<string> { AppContext.BaseDirectory };
var current = new DirectoryInfo(AppContext.BaseDirectory);
for (var i = 0; i < 6 && current.Parent != null; i++)
{
current = current.Parent;
roots.Add(current.FullName);
}
foreach (var root in roots.Distinct(StringComparer.OrdinalIgnoreCase))
{
foreach (var relativeDirectory in new[]
{
string.Empty,
"ExternalLibraries",
Path.Combine("ExternalLibraries", "Host"),
"ReleaseFiles",
Path.Combine("ReleaseFiles", "Host")
})
{
var candidate = Path.Combine(root, relativeDirectory, fileName);
if (File.Exists(candidate))
return candidate;
}
}
return Path.Combine(AppContext.BaseDirectory, fileName);
}
/// <summary>读取应用目录中的原生依赖版本信息。</summary>
/// <param name="category">依赖类别。</param>
/// <param name="displayName">显示名称。</param>
@@ -700,9 +700,9 @@ namespace XplorePlane.Services.Cnc
bool succeeded,
string message)
{
_eventAggregator.GetEvent<StatusBarMessageEvent>().Publish(
_eventAggregator.GetEvent<StatusBarMessageEvent>()?.Publish(
new StatusBarMessagePayload(message, !succeeded, 0));
_eventAggregator.GetEvent<TemplateMatchPreviewResultEvent>().Publish(
_eventAggregator.GetEvent<TemplateMatchPreviewResultEvent>()?.Publish(
new TemplateMatchPreviewPayload
{
IsAlignmentResult = true,
@@ -2621,12 +2621,16 @@ namespace XplorePlane.Services.Cnc
roiResult.TransformedPointsInt?.Count ?? 0, "", order++));
}
await _archive.AppendNodeResultAsync(nodeResult, metrics: metrics);
}
catch (Exception ex)
{
_logger.ForModule<CncExecutionService>().Warn("对齐节点结果归档失败:{0}", ex.Message);
await _archive.AppendNodeResultAsync(
nodeResult,
metrics,
pipelineSnapshot: null,
assets: null);
}
catch (Exception ex)
{
_logger.ForModule<CncExecutionService>().Warn("对齐节点结果归档失败:{0}", ex.Message);
}
}
/// <summary>构造一个通用数值度量项(默认视为通过,不参与判定)。</summary>
@@ -227,13 +227,7 @@ namespace XplorePlane.Services.Inspection
BuildTileImages(orderedTiles, tileImages),
rawOutcome.ResultImage16);
// 运行时发布 Transforms 供主视口 Overlay 使用
PublishRuntime(new InspectionPoolRuntimePayload(
InspectionPoolRuntimeStage.TileCompleted,
definition,
TileId: "_stitched",
Image: stitchResult.StitchedImage,
TileTransforms: stitchResult.TileTransforms));
// 拼接结果通过 outcome 返回给调用方,避免再次发布 TileCompleted(该阶段只表示单个 Tile 完成)。
}
catch (Exception ex)
{
@@ -398,19 +392,10 @@ namespace XplorePlane.Services.Inspection
return await _acquisitionService.AcquireAsync(machine, acquisition, cancellationToken)
.ConfigureAwait(false);
}
catch (OperationCanceledException) when (!cancellationToken.IsCancellationRequested)
catch (OperationCanceledException)
{
// 采集超时
var action = _poolInteraction.OnTileFailed(tileId, "采集超时", false);
switch (action)
{
case TileInteractionResult.Retry:
continue;
case TileInteractionResult.Skip:
return null; // 跳过 = 丢失一个 Tile
case TileInteractionResult.Abort:
throw new OperationCanceledException($"Tile [{tileId}] 用户中止");
}
// 采集服务抛出的取消必须向上传播,确保检测池总能执行 Restore。
throw;
}
catch (Exception ex) when (ex is not OperationCanceledException)
{
@@ -199,11 +199,13 @@ WHERE run_id = @run_id";
}
public InspectionResultStoreCore(IDbContext db, ILoggerService logger, IXpDataPathService dataPathService, IInspectionAssetPathResolver pathResolver = null)
: this(
db,
logger,
dataPathService?.DataPath ?? throw new ArgumentNullException(nameof(dataPathService)),
pathResolver)
: this(
db,
logger,
Path.Combine(
dataPathService?.DataPath ?? throw new ArgumentNullException(nameof(dataPathService)),
"InspectionResults"),
pathResolver)
{
}
@@ -307,10 +307,10 @@ namespace XplorePlane.Services.Main.Recording
/// <summary>
/// 构造 VIDEO 文件夹完整路径
/// </summary>
internal static string GetVideoFolderPath(string rootPath)
{
return Path.Combine(rootPath, "Results", "Video");
}
internal static string GetVideoFolderPath(string rootPath)
{
return Path.Combine(rootPath, "VIDEO");
}
/// <summary>
/// 将总秒数格式化为 "MM:SS" 计时器显示文本
@@ -156,14 +156,16 @@ namespace XplorePlane.Services.Reporting
OperatorName = EmptyText,
Description = FallbackText(run.ProgramName)
},
// 不指定 TemplatePathOverride,使用默认的 StandardReportTemplate | No override, use default StandardReportTemplate
// CNC 报告使用专用模板:首页 + 按检测节点重复展开详情页。
TemplatePathOverride = CncTemplateRelativePath,
Formats = new List<ReportOutputFormat> { ReportOutputFormat.Pdf },
CustomProperties = BuildHomepageProperties(run, reportableNodes.Count, overallResult, runSummaryRows, nodeSections),
FileNameParameters = new Dictionary<string, string>
{
["ProgramName"] = (run.ProgramName ?? string.Empty).Trim(),
["WorkpieceId"] = (run.WorkpieceId ?? string.Empty).Trim(),
["SerialNumber"] = (run.SerialNumber ?? string.Empty).Trim(),
["WorkpieceId"] = (run.WorkpieceId ?? string.Empty).Trim(),
["SerialNumber"] = (run.SerialNumber ?? string.Empty).Trim(),
["WorkpieceSN"] = (run.SerialNumber ?? string.Empty).Trim(),
["Result"] = overallResult,
["StartDate"] = run.StartedAt != default ? ToLocal(run.StartedAt).ToString("yyyyMMdd") : "",
["StartTime"] = run.StartedAt != default ? ToLocal(run.StartedAt).ToString("HHmmss") : "",
@@ -223,7 +225,10 @@ namespace XplorePlane.Services.Reporting
// 综合判定(完整行含前缀)| Overall result (full line with label)
props["hpOverallLine"] = $"综合判定 | Overall{overallResult}";
props["overallResult"] = overallResult;
props["overallResult"] = overallResult;
// 保留旧版报告模板/调用方使用的简短键名,避免模板升级造成兼容性破坏。
props["programName"] = (run.ProgramName ?? string.Empty).Trim();
props["inspectionNodeCount"] = reportableNodeCount;
// 汇总表标题 | Summary table title
props["hpSummaryTitle"] = runSummaryRows.Count > 0 ? "节点结果汇总 | Node Summary" : string.Empty;
@@ -733,7 +733,7 @@ public class TemplateMatchAlignmentNodeEditorViewModel : BindableBase, IDisposab
if (string.IsNullOrWhiteSpace(programPath) && !string.IsNullOrWhiteSpace(_cncProgramName))
programPath = Path.Combine(_dataPathService.PlanPath, _cncProgramName + ".xpcnc");
string dir = string.IsNullOrWhiteSpace(programPath)
? Path.Combine(_dataPathService.PlanPath, "UnboundCnc.assets", "Templates")
? Path.Combine(_dataPathService.ToolsPath, "Templates")
: Path.Combine(Path.GetDirectoryName(Path.GetFullPath(programPath))!, Path.GetFileNameWithoutExtension(programPath) + ".assets", "Templates");
Directory.CreateDirectory(dir);
string fileName = $"{_nodeId:N}_template.png";
@@ -1397,6 +1397,7 @@ namespace XplorePlane.ViewModels.Cnc
}
finally
{
ResetAllNodeStates();
IsRunning = false;
_cts?.Dispose();
_cts = null;