import { describe, expect, it } from "vitest"; import { buildRunBundle, formatNumber, generateParamsBlock, getMethod, isPlainStruct, withEdits, LIBRARY_FILES, validateSpec, } from "../src/index"; import { runner, testSpec } from "./helpers"; describe("source generation and editing", () => { it("formats numbers as exact, readable MATLAB literals", () => { expect(formatNumber(200e9)).toBe("200e9"); expect(formatNumber(0.002)).toBe("0.002"); expect(formatNumber(44100)).toBe("44100"); expect(formatNumber(1e-3)).toBe("0.001"); expect(formatNumber(2.5e-7)).toBe("250e-9"); expect(formatNumber(7850)).toBe("7850"); expect(Number(formatNumber(68.9e9))).toBe(68.9e9); expect(formatNumber(-3)).toBe("-3"); }); it("round-trips the spec through the params block", async () => { const spec = testSpec(); const block = generateParamsBlock(spec); const bundle = { files: [{ name: "p.m", source: block }, ...LIBRARY_FILES], entry: "p.m", resultVariable: "params", }; const run = await runner.run({ bundle }); expect(run.ok).toBe(true); if (!run.ok || !isPlainStruct(run.value)) return; const plate = run.value.fields.plate; const mat = run.value.fields.material; if (!isPlainStruct(plate) || !isPlainStruct(mat)) throw new Error("params fields are not structs"); expect(plate.fields.h).toBe(spec.plate.h); expect(mat.fields.E).toBe(spec.material.E); expect(mat.fields.name).toBe(spec.material.name); }); it("runs the edited source, and surfaces numbl errors with file and line", async () => { const spec = testSpec(); const bundle = buildRunBundle(spec, getMethod("fd")); const main = bundle.files.find((f) => f.name === "main.m")!.source; const edited = withEdits(bundle, { "main.m": main.replace("result = plate_fd(params);", "result = plate_fd(params)\nresult = undefined_function_xyz(1);") }); const run = await runner.run({ bundle: edited }); expect(run.ok).toBe(false); if (run.ok) return; expect(run.error).toMatch(/undefined_function_xyz/); expect(run.error).toMatch(/main\.m/); }); it("reports a missing result variable rather than an empty screen", async () => { const spec = testSpec(); const bundle = buildRunBundle(spec, getMethod("fd")); const edited = withEdits(bundle, { "main.m": "x = 1;" }); const run = await runner.run({ bundle: edited }); expect(run.ok).toBe(false); if (!run.ok) expect(run.error).toMatch(/result/); }); it("validates obviously bad specs", () => { const spec = testSpec(); spec.probe.x = 10; spec.fd.cfl = 1.2; const issues = validateSpec(spec); expect(issues.some((i) => i.path === "probe" && i.severity === "error")).toBe(true); expect(issues.some((i) => i.path === "fd.cfl" && i.severity === "warning")).toBe(true); }); });