Files
KDL_WORK/kdl-wasm/web/tests/reports/report.test.ts
2026-06-28 08:20:33 +08:00

150 lines
4.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { postProcessBrand } from "../../src/grl/post/index.js";
import { parseGrl } from "../../src/grl/parser/index.js";
import { compileSemanticProgram } from "../../src/grl/semantic/index.js";
import { pathOperationToGrl, sampleOlpProject } from "../../src/olp/index.js";
import {
calibrationSummary,
createValidationReport,
exportCustomerDeliveryPackage,
exportValidationReportHtml,
serializeDeliveryPackage,
validateReportSchema
} from "../../src/reports/index.js";
const NOW = "2026-06-27T00:00:00.000Z";
describe("validation reports and customer delivery", () => {
it("creates stable validation report sections for reachability, cycle, IO/Wait, post, import, and calibration", () => {
const project = sampleOlpProject();
const report = createValidationReport({
id: "demo_validation",
project,
generatedAt: NOW,
pathValidation: {
ok: true,
reachable: true,
cycleTime: 4.2,
segmentReports: [],
diagnostics: []
},
ioWaitDiagnostics: [],
postDiagnostics: [],
importDiagnostics: [
{
severity: "info",
code: "IMPORT_OK",
message: "ABB import mapped to OLP",
sourceMap: { file: "imports/PickPlace.mod", line: 8 }
}
]
});
expect(validateReportSchema(report)).toEqual({ ok: true, issues: [] });
expect(report.status).toBe("pass");
expect(report.sections.map((section) => section.name)).toEqual([
"reachability",
"cycle_time",
"io_wait",
"post",
"import",
"collision",
"calibration"
]);
expect(report.sections.find((section) => section.name === "cycle_time")?.summary).toEqual({
cycleTime: 4.2,
trajectories: 0
});
expect(report.sourceMap).toEqual([
{
kind: "IMPORT_OK",
id: "IMPORT_OK-0",
file: "imports/PickPlace.mod",
line: 8
}
]);
});
it("exports openable HTML with summary, details, and source map payload", () => {
const report = createValidationReport({
id: "demo_validation",
project: sampleOlpProject(),
generatedAt: NOW,
diagnostics: [
{
severity: "info",
code: "REACH_OK",
message: "pick target reachable",
sourceMap: { file: "source/DemoCell.grl", line: 20 }
}
]
});
const html = exportValidationReportHtml(report);
expect(html).toContain("<!doctype html>");
expect(html).toContain("Status: warn");
expect(html).toContain("reachability");
expect(html).toContain("source/DemoCell.grl");
expect(html).toContain("validation-report-json");
});
it("exports customer delivery package with source, brand programs, IO map, reports, calibration, and trace", () => {
const project = sampleOlpProject();
const grl = pathOperationToGrl(project, "pick_op", { moduleName: "DemoCell" });
project.programs.push(grl.program);
const ir = compileSemanticProgram(parseGrl(grl.text), {
startJoints: [0, 0, 0, 0, 0, 0],
sampleTime: 0.004
});
const abb = postProcessBrand(ir, "abb");
const report = createValidationReport({
id: "demo_validation",
project,
generatedAt: NOW,
postDiagnostics: abb.report.map((issue) => ({
severity: issue.severity,
code: issue.code,
message: issue.message
})),
pathValidation: {
ok: true,
reachable: true,
cycleTime: 4.2,
segmentReports: [],
diagnostics: []
}
});
const pkg = exportCustomerDeliveryPackage({
project,
report,
trace: { samples: ["t=0 movej home"] },
brandPrograms: { [abb.filename]: abb.text },
ioMap: { "io.do[1]": "vacuum" }
});
const serialized = serializeDeliveryPackage(pkg);
expect(pkg.manifest).toEqual({
sourcePrograms: ["source/pick_op_grl.grl"],
brandPrograms: ["post/DemoCell.mod"],
reports: ["reports/demo_validation.html", "reports/demo_validation.json"],
calibrationFiles: ["calibration/calibrations.json"],
traceFiles: ["trace/trace.json"],
ioMaps: ["io/io_map.json"]
});
expect(pkg.files.map((file) => file.path)).toEqual([
"calibration/calibrations.json",
"io/io_map.json",
"post/DemoCell.mod",
"project/project.json",
"reports/demo_validation.html",
"reports/demo_validation.json",
"source/pick_op_grl.grl",
"trace/trace.json"
]);
expect(serialized).toContain("\"format\": \"customer-delivery/0.1\"");
expect(serialized).toContain("fnv1a32:");
expect(calibrationSummary(project.calibrations)).toEqual({ tcp: 1 });
});
});