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