From c6b237035e536b8b585aee364ee8859a6b431447 Mon Sep 17 00:00:00 2001 From: multipleof4 Date: Fri, 6 Feb 2026 14:03:52 -0800 Subject: [PATCH] Feat: Add multi-dependency MST pipeline test --- tests/12_mst_pipeline/test.js | 104 ++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 tests/12_mst_pipeline/test.js diff --git a/tests/12_mst_pipeline/test.js b/tests/12_mst_pipeline/test.js new file mode 100644 index 0000000..041e9b4 --- /dev/null +++ b/tests/12_mst_pipeline/test.js @@ -0,0 +1,104 @@ +export default { + functionName: 'computeMST', + prompt: `// Write an async JavaScript function 'computeMST' that parses a TOML config describing weighted graph edges, computes the Minimum Spanning Tree using Kruskal's algorithm, and returns the result as a formatted ASCII table. +// - The function must accept a TOML string. +// - You MUST use dynamic import() to load ALL THREE of these libraries from CDNs: +// 1. 'smol-toml' — to parse the TOML string into a JS object. +// 2. 'mnemonist' — to use its Heap (min-heap by weight) for sorting edges, AND its SparseQueueSet or similar union-find approach. Actually, mnemonist does not have union-find, so implement a simple union-find yourself (with path compression and union by rank), but you MUST use mnemonist's Heap to process edges in weight order. +// 3. 'text-table' — to format the final MST edges as an aligned ASCII table. +// +// TOML format: +// [[edges]] +// from = "A" +// to = "B" +// weight = 4 +// +// [[edges]] +// from = "B" +// to = "C" +// weight = 2 +// ... etc +// +// Algorithm (Kruskal's): +// 1. Parse the TOML to extract the edges array. +// 2. Push all edges into a mnemonist Heap (min-heap), comparing by weight. +// 3. Initialize a union-find for all unique node names found in edges. +// 4. Pop edges from the heap in ascending weight order. For each edge, if 'from' and 'to' are in different sets, union them and add the edge to the MST. +// 5. Continue until MST has (number_of_nodes - 1) edges or heap is empty. +// +// Output: +// - Collect MST edges as arrays: [from, to, String(weight)] in the order they were added. +// - Prepend a header row: ['From', 'To', 'Weight']. +// - Pass this array-of-arrays to text-table to produce an aligned ASCII string. +// - Return an object: { table: string, totalWeight: number } +// where 'table' is the text-table output and 'totalWeight' is the sum of MST edge weights.`, + runTest: async (computeMST) => { + const assert = { + strictEqual: (a, e, m) => { if (a !== e) throw new Error(m || `FAIL: ${a} !== ${e}`) }, + ok: (v, m) => { if (!v) throw new Error(m) }, + }; + + const toml = ` +[[edges]] +from = "A" +to = "B" +weight = 4 + +[[edges]] +from = "A" +to = "C" +weight = 2 + +[[edges]] +from = "B" +to = "C" +weight = 5 + +[[edges]] +from = "B" +to = "D" +weight = 10 + +[[edges]] +from = "C" +to = "D" +weight = 3 + +[[edges]] +from = "C" +to = "E" +weight = 8 + +[[edges]] +from = "D" +to = "E" +weight = 7 +`; + + const result = await computeMST(toml); + + assert.ok(result && typeof result === 'object', 'Should return an object'); + assert.ok(typeof result.table === 'string', 'table should be a string'); + assert.ok(typeof result.totalWeight === 'number', 'totalWeight should be a number'); + + // MST of this graph: + // A-C (2), C-D (3), A-B (4), D-E (7) = total 16 + assert.strictEqual(result.totalWeight, 16, `Total MST weight should be 16, got ${result.totalWeight}`); + + const lines = result.table.trim().split('\n').map(l => l.trim()); + assert.strictEqual(lines.length, 5, `Table should have 5 lines (1 header + 4 edges), got ${lines.length}`); + assert.ok(lines[0].includes('From') && lines[0].includes('To') && lines[0].includes('Weight'), 'First line should be header row'); + + const edgeLines = lines.slice(1); + const parsed = edgeLines.map(l => { + const parts = l.split(/\s+/).filter(Boolean); + return { from: parts[0], to: parts[1], w: parseInt(parts[2], 10) }; + }); + const weights = parsed.map(e => e.w).sort((a, b) => a - b); + assert.strictEqual(JSON.stringify(weights), JSON.stringify([2, 3, 4, 7]), `MST edge weights should be [2,3,4,7], got [${weights}]`); + + const nodes = new Set(); + parsed.forEach(e => { nodes.add(e.from); nodes.add(e.to); }); + assert.strictEqual(nodes.size, 5, `MST should span all 5 nodes, got ${nodes.size}`); + } +};