import test from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";
const { digestPlan, PlanError, digestForModel } = await import("../lib/digest.ts");
export const PLAN = `
GoodEnoughPlanFound
Could Not Generate Valid Parallel Plan
`;
test("digests what matters in a showplan", () => {
const d = digestPlan(PLAN);
assert.match(d.sql, /o\.Total > 500/, "XML entities decoded");
assert.equal(d.subtreeCost, 4.871);
assert.equal(d.earlyAbort, "GoodEnoughPlanFound");
assert.equal(d.nonParallelReason, "Could Not Generate Valid Parallel Plan");
assert.deepEqual(d.tables, ["wide.Sales.Orders", "wide.Sales.Customer"]);
assert.equal(d.topOperators[0].op, "Clustered Index Scan");
assert.equal(d.topOperators[0].spillLevels, 2);
assert.equal(d.topOperators[0].actualRows, 1243500);
assert.equal(d.topOperators[0].parallel, false);
assert.deepEqual(d.missingIndexes[0], { table: "wide.Sales.Orders", equality: ["CustomerId"],
inequality: ["Total"], included: ["Id"], impact: 94.17 });
assert.ok(d.warnings.includes("NoJoinPredicate"));
assert.ok(d.warnings.some((w) => w.startsWith("SpillToTempDb")));
assert.deepEqual(d.waits, [{ type: "PAGEIOLATCH_SH", ms: 812 }]);
assert.ok(d.rowGuessErrors[0].ratio > 100);
assert.equal(d.bytes, PLAN.length);
});
test("a BOM-prefixed plan still digests — SSMS writes .sqlplan as UTF-16 with a BOM", () => {
assert.equal(digestPlan("\uFEFF" + PLAN).subtreeCost, 4.871);
});
test("rejects input that is not a plan", () => {
for (const bad of ["", "SELECT 1", "", " digestPlan(bad), PlanError);
});
test("digestForModel stays bounded on a fat plan", () => {
const big = `` +
Array.from({ length: 400 }, (_, i) =>
``).join("") +
``;
const v = digestForModel(digestPlan(big)) as { topOperators: unknown[]; tables: unknown[] };
assert.ok(v.topOperators.length <= 12);
});
test("a real .sqlplan digests", () => {
let xml: string;
try { xml = readFileSync("fixtures/real.sqlplan", "utf8"); } catch { return console.log("skip: no fixtures/real.sqlplan"); }
const d = digestPlan(xml);
assert.ok(d.topOperators.length > 0, "no operators found — check attribute spellings");
assert.ok(d.sql.length > 0);
});