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(""); 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 }); }); });