Something went wrong. Try again.
A functional toolkit for authoring resource-leveling algorithms — compose constraint and scoring blocks, enumerate feasible schedules
Something went wrong. Try again.
4.8 kB · 166 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167import { test, expect, describe } from "bun:test";
import { createRegistry } from "../../src/level-blocks/registry.ts";import { pipelineGraphSchema, validateGraph, type PipelineGraph,} from "../../src/level-blocks/graph.ts";
import { makeDefs } from "./pipelineFixtures.ts";
const registry = createRegistry(makeDefs());
function makeGraph(): PipelineGraph { return { formatVersion: 1, systemCode: "OHT", blocks: [ { instanceId: "b1", code: "ToyCap", params: { resource: "crane", max: 2 }, provenance: "curated", shadow: true, }, { instanceId: "b2", code: "ToyWeight", params: { weight: 0.5 }, provenance: "candidate", shadow: false, }, { instanceId: "b3", code: "ToyGreedy", params: { seed: 7 }, provenance: "curated", shadow: false, }, ], };}
describe("pipelineGraphSchema", () => { test("applies provenance/shadow defaults", () => { const parsed = pipelineGraphSchema.parse({ formatVersion: 1, blocks: [{ instanceId: "b1", code: "ToyCap", params: {} }], }); expect(parsed.blocks[0]!.provenance).toBe("curated"); expect(parsed.blocks[0]!.shadow).toBe(false); });
test("rejects unknown formatVersion", () => { expect(() => pipelineGraphSchema.parse({ formatVersion: 2, blocks: [] }), ).toThrow(); });});
describe("validateGraph — round trip", () => { test("build → stringify → parse → validate → deep-equal", () => { const graph = makeGraph(); const revived: unknown = JSON.parse(JSON.stringify(graph)); const result = validateGraph(registry, revived); expect(result.ok).toBe(true); if (result.ok) expect(result.graph).toEqual(graph); });
test("accepts a graph without optional systemCode", () => { const graph = makeGraph(); delete graph.systemCode; const result = validateGraph(registry, JSON.parse(JSON.stringify(graph))); expect(result.ok).toBe(true); });});
describe("validateGraph — rejections", () => { test("rejects non-graph values with shape issues", () => { const result = validateGraph(registry, { nope: true }); expect(result.ok).toBe(false); if (!result.ok) expect(result.issues.length).toBeGreaterThan(0); });
test("rejects unknown block codes", () => { const graph = makeGraph(); graph.blocks[0]!.code = "Mystery"; const result = validateGraph(registry, graph); expect(result.ok).toBe(false); if (!result.ok) { expect(result.issues).toContainEqual({ instanceId: "b1", code: "Mystery", message: "Unknown block code: Mystery", }); } });
test("rejects params that fail the block input schema", () => { const graph = makeGraph(); graph.blocks[0]!.params = { resource: "crane", max: -1 }; const result = validateGraph(registry, graph); expect(result.ok).toBe(false); if (!result.ok) { expect( result.issues.some( (i) => i.instanceId === "b1" && i.message.includes("Invalid params"), ), ).toBe(true); } });
test("rejects a graph with zero search blocks", () => { const graph = makeGraph(); graph.blocks = graph.blocks.filter((b) => b.code !== "ToyGreedy"); const result = validateGraph(registry, graph); expect(result.ok).toBe(false); if (!result.ok) { expect( result.issues.some((i) => i.message.includes("exactly one search")), ).toBe(true); } });
test("rejects a graph with two search blocks", () => { const graph = makeGraph(); graph.blocks.push({ instanceId: "b4", code: "ToyGreedy", params: { seed: 8 }, provenance: "curated", shadow: false, }); const result = validateGraph(registry, graph); expect(result.ok).toBe(false); if (!result.ok) { expect(result.issues.some((i) => i.message.includes("found 2"))).toBe( true, ); } });
test("rejects duplicate instanceIds", () => { const graph = makeGraph(); graph.blocks[1]!.instanceId = "b1"; const result = validateGraph(registry, graph); expect(result.ok).toBe(false); if (!result.ok) { expect( result.issues.some((i) => i.message.includes("Duplicate instanceId: b1"), ), ).toBe(true); } });
test("collects multiple issues in one pass", () => { const graph = makeGraph(); graph.blocks[0]!.code = "Mystery"; graph.blocks[1]!.params = { weight: -1 }; graph.blocks = graph.blocks.filter((b) => b.code !== "ToyGreedy"); const result = validateGraph(registry, graph); expect(result.ok).toBe(false); if (!result.ok) expect(result.issues.length).toBeGreaterThanOrEqual(3); });});