~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/atlibs

0
0
main
49 lines · 2.9 KB Raw History
// node --test javascript/src/compose/build.test.mjs   (deno for the type checks; skipped without it)
import assert from "node:assert/strict";
import { execFileSync, spawnSync } from "node:child_process";
import { readFileSync } from "node:fs";
import { test } from "node:test";

import { compose } from "../../../examples/rust/compose/atlibs.modules.js";
import { composition } from "./build.js";

const example = new URL("../../../examples/rust/compose/", import.meta.url);

test("compose.ts writes the composition.json beside it", () => {
	const out = execFileSync(process.execPath, ["compose.ts"], { cwd: example, encoding: "utf8" });
	assert.equal(out, readFileSync(new URL("composition.json", example), "utf8"));
});

test("build() runs the hosts' load checks and points at the line that made the instance or route", async () => {
	const lineOf = (re) => readFileSync(new URL(import.meta.url), "utf8").split("\n").findIndex((l) => re.test(l)) + 1;
	const refused = async (c, msg, marker) => assert.rejects(c.build(), (e) => e.message.startsWith(`composition: ${msg}`) && e.message.endsWith(`build.test.mjs:${lineOf(marker)}:${e.message.split(":").at(-1)}`), msg);

	const a = composition({ name: "a" });
	a.route(a.instance("ui", compose), "com.example.compose.confirm", a.instance("x", compose)); // confirm-route
	await refused(a, "edge ui com.example.compose.confirm: x (compose) does not implement com.example.compose.confirm", /confirm-route$/);

	const b = composition({ name: "b" });
	b.instance("x", compose, { input: { n: "0" } }); // string-n
	await refused(b, "instance x: input n must be of type integer", /string-n$/);

	const c = composition({ name: "c" });
	const ui = c.instance("ui", compose);
	const x = c.instance("x", compose);
	c.route(ui, "com.example.compose.lookup", x);
	c.route(ui, "com.example.compose.lookup", x); // twice
	await refused(c, "edge ui com.example.compose.lookup: routed twice", /twice$/);

	const ok = composition({ name: "ok" });
	ok.route(ok.instance("ui", compose), "com.example.compose.lookup", ok.instance("x", compose, { input: { n: 1 } }));
	assert.deepEqual((await ok.build()).edges, [{ from: "ui", nsid: "com.example.compose.lookup", to: "x", reason: "the example's lookup: another instance doubles n" }]);
});

const deno = spawnSync("deno", ["--version"]).status === 0;
test("types: wrong.ts's marked lines are type errors, compose.ts has none", { skip: !deno && "no deno" }, () => {
	const check = (file) => spawnSync("deno", ["check", file], { cwd: example, encoding: "utf8", env: { ...process.env, NO_COLOR: "1" } });
	assert.equal(check("compose.ts").status, 0);
	const out = check("wrong.ts").stderr;
	const marked = readFileSync(new URL("wrong.ts", example), "utf8").split("\n").flatMap((l, i) => (l.includes("// ✗") ? [i + 1] : []));
	const errors = [...new Set([...out.matchAll(/wrong\.ts:(\d+):\d+/g)].map((m) => Number(m[1])))];
	assert.deepEqual(errors, marked, out);
});