Add ABB120 demo suite and docs
This commit is contained in:
101
kdl-wasm/web/scripts/run-abb120-spec-suite.ts
Normal file
101
kdl-wasm/web/scripts/run-abb120-spec-suite.ts
Normal file
@@ -0,0 +1,101 @@
|
||||
import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { runAbb120SpecSuite } from "../src/suites/abb120SpecSuite.js";
|
||||
|
||||
const webRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
const specRoot = join(webRoot, "tests", "fixtures", "abb120", "spec-programs");
|
||||
const manifest = JSON.parse(readFileSync(join(specRoot, "manifest.json"), "utf8"));
|
||||
const programs = manifest.programs.map((entry: { program_id: string; file: string }) => ({
|
||||
program_id: entry.program_id,
|
||||
file: entry.file,
|
||||
text: readFileSync(join(specRoot, entry.file), "utf8")
|
||||
}));
|
||||
const job = runAbb120SpecSuite(manifest, programs, {
|
||||
gitRevision: process.env.GIT_REVISION ?? "working-tree"
|
||||
});
|
||||
const outputRoot = resolve(webRoot, "test-results", "abb120-spec", job.job_id);
|
||||
|
||||
mkdirSync(outputRoot, { recursive: true });
|
||||
writeFileSync(join(outputRoot, "manifest.json"), `${JSON.stringify(manifest, null, 2)}\n`);
|
||||
writeFileSync(join(outputRoot, "job.json"), `${JSON.stringify(job, null, 2)}\n`);
|
||||
writeFileSync(join(outputRoot, "report.json"), `${JSON.stringify(reportJson(job), null, 2)}\n`);
|
||||
writeFileSync(join(outputRoot, "report.html"), reportHtml(job));
|
||||
|
||||
for (const program of job.programs) {
|
||||
const programDir = join(outputRoot, "programs", program.program_id);
|
||||
mkdirSync(programDir, { recursive: true });
|
||||
writeFileSync(join(programDir, "compile.json"), `${JSON.stringify(program.compile, null, 2)}\n`);
|
||||
writeFileSync(join(programDir, "controller.json"), `${JSON.stringify(program.controller ?? {}, null, 2)}\n`);
|
||||
writeFileSync(join(programDir, "motion-queue.json"), `${JSON.stringify(program.motionQueue ?? {}, null, 2)}\n`);
|
||||
writeFileSync(join(programDir, "trace.json"), `${JSON.stringify(program.trace ?? [], null, 2)}\n`);
|
||||
writeFileSync(join(programDir, "io.json"), `${JSON.stringify(program.io ?? {}, null, 2)}\n`);
|
||||
writeFileSync(join(programDir, "trajectory.json"), `${JSON.stringify(program.trajectory ?? {}, null, 2)}\n`);
|
||||
writeFileSync(join(programDir, "post-report.json"), `${JSON.stringify(program.post ?? {}, null, 2)}\n`);
|
||||
writeFileSync(join(programDir, "roundtrip.json"), `${JSON.stringify(program.roundtrip ?? {}, null, 2)}\n`);
|
||||
}
|
||||
|
||||
console.log(JSON.stringify({
|
||||
job_id: job.job_id,
|
||||
outputRoot,
|
||||
programs: job.programs.length,
|
||||
missingSections: job.coverage.missingSections
|
||||
}, null, 2));
|
||||
|
||||
function reportJson(job: ReturnType<typeof runAbb120SpecSuite>) {
|
||||
return {
|
||||
job_id: job.job_id,
|
||||
suite_id: job.suite_id,
|
||||
robot_id: job.robot_id,
|
||||
coverage: job.coverage,
|
||||
summary: {
|
||||
programs: job.programs.length,
|
||||
pass: job.programs.filter((program) => program.status === "pass").length,
|
||||
diagnostic: job.programs.filter((program) => program.status === "diagnostic").length,
|
||||
fail: job.programs.filter((program) => program.status === "fail").length
|
||||
},
|
||||
diagnostics: job.programs.flatMap((program) =>
|
||||
program.diagnostics.map((diagnostic) => ({
|
||||
program_id: program.program_id,
|
||||
...diagnostic
|
||||
}))
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
function reportHtml(job: ReturnType<typeof runAbb120SpecSuite>): string {
|
||||
const rows = job.programs.map((program) =>
|
||||
`<tr><td>${escapeHtml(program.program_id)}</td><td>${escapeHtml(program.coverage_level)}</td><td>${escapeHtml(program.status)}</td><td>${program.diagnostics.length}</td></tr>`
|
||||
).join("\n");
|
||||
return `<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>${escapeHtml(job.job_id)}</title>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; margin: 24px; color: #1f2933; }
|
||||
table { border-collapse: collapse; width: 100%; }
|
||||
th, td { border: 1px solid #ccd5dd; padding: 8px; text-align: left; }
|
||||
th { background: #eef2f4; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>${escapeHtml(job.job_id)}</h1>
|
||||
<p>Suite ${escapeHtml(job.suite_id)} / Robot ${escapeHtml(job.robot_id)}</p>
|
||||
<p>Covered sections: ${job.coverage.coveredSections.join(", ")}</p>
|
||||
<table>
|
||||
<thead><tr><th>Program</th><th>Layer</th><th>Status</th><th>Diagnostics</th></tr></thead>
|
||||
<tbody>${rows}</tbody>
|
||||
</table>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
}
|
||||
|
||||
function escapeHtml(value: unknown): string {
|
||||
return String(value)
|
||||
.replaceAll("&", "&")
|
||||
.replaceAll("<", "<")
|
||||
.replaceAll(">", ">")
|
||||
.replaceAll("\"", """);
|
||||
}
|
||||
Reference in New Issue
Block a user