import { afterAll, beforeAll, describe, expect, test } from "bun:test"; import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { resolve } from "node:path"; import { computeRustGraphDepth, parseCargoToml, } from "./c14_rust_graph_depth.ts"; const FIXTURE = mkdtempSync(resolve(tmpdir(), "tdd-md-rust-graph-")); const writeFile = (rel: string, content: string): void => { const abs = resolve(FIXTURE, rel); mkdirSync(abs.split("/").slice(0, -1).join("/"), { recursive: true }); writeFileSync(abs, content); }; beforeAll(() => { // Fixture: a workspace with a root crate + three member crates. // Dependency chain: root → middle → leaf, with `core` standalone. // root (top) // └─→ middle (path) // └─→ leaf (workspace = true) // core (no internal deps) writeFile( "Cargo.toml", `[package] name = "rootcrate" version = "0.1.0" edition = "2021" [workspace] members = [ "crates/middle", "crates/leaf", "crates/core", ] [workspace.dependencies] leaf = { version = "0.1", path = "crates/leaf" } [dependencies] middle = { version = "0.1", path = "crates/middle" } serde = "1.0" `, ); writeFile( "crates/middle/Cargo.toml", `[package] name = "middle" version = "0.1.0" edition = "2021" [dependencies] leaf = { workspace = true } anyhow = "1.0" `, ); writeFile( "crates/leaf/Cargo.toml", `[package] name = "leaf" version = "0.1.0" edition = "2021" [dependencies] log = "0.4" `, ); writeFile( "crates/core/Cargo.toml", `[package] name = "core" version = "0.1.0" edition = "2021" [dependencies] log = "0.4" `, ); }); afterAll(() => { rmSync(FIXTURE, { recursive: true, force: true }); }); describe("parseCargoToml", () => { test("extracts a simple [package] name", () => { const doc = parseCargoToml(`[package]\nname = "myseg"\nversion = "0.1.0"\n`); const pkg = doc.sections.get("package"); expect(pkg?.get("name")).toBe("myseg"); }); test("extracts a multi-line workspace.members array", () => { const doc = parseCargoToml(`[workspace] members = [ "crates/a", "crates/b", ] `); const ws = doc.sections.get("workspace"); expect(ws?.get("members")).toEqual(["crates/a", "crates/b"]); }); test("parses an inline-table dependency spec", () => { const doc = parseCargoToml(`[dependencies] mydep = { version = "0.1", path = "crates/mydep" } `); const deps = doc.sections.get("dependencies"); const spec = deps?.get("mydep") as Record; expect(spec.version).toBe("0.1"); expect(spec.path).toBe("crates/mydep"); }); test("parses workspace = true dep style", () => { const doc = parseCargoToml(`[dependencies] foo = { workspace = true } `); const deps = doc.sections.get("dependencies"); const spec = deps?.get("foo") as Record; expect(spec.workspace).toBe("true"); }); }); describe("computeRustGraphDepth — end-to-end on fixture", () => { test("root → middle → leaf chain produces depth 3", () => { const r = computeRustGraphDepth(FIXTURE); expect(r.language).toBe("rust"); expect(r.workspaceName).toBe("rootcrate"); // 4 crates: rootcrate, middle, leaf, core. expect(r.nodeCount).toBe(4); // 2 internal edges: rootcrate → middle, middle → leaf. // (core has no internal deps; serde/anyhow/log are external.) expect(r.edgeCount).toBe(2); expect(r.depth).toBe(3); }); test("standalone core crate doesn't contribute to longest path", () => { const r = computeRustGraphDepth(FIXTURE); // core is included as a node (depth-1 leaf) but does not extend // the longest chain. Longest is still rootcrate → middle → leaf. expect(r.depth).toBe(3); }); test("re-running on the same workspace produces identical numbers", () => { const a = computeRustGraphDepth(FIXTURE); const b = computeRustGraphDepth(FIXTURE); expect(a).toEqual(b); }); }); describe("computeRustGraphDepth — virtual workspace (no root [package])", () => { const VW = mkdtempSync(resolve(tmpdir(), "tdd-md-rust-virtual-")); const writeVW = (rel: string, content: string): void => { const abs = resolve(VW, rel); mkdirSync(abs.split("/").slice(0, -1).join("/"), { recursive: true }); writeFileSync(abs, content); }; beforeAll(() => { writeVW( "Cargo.toml", `[workspace] members = ["crates/a", "crates/b"] `, ); writeVW( "crates/a/Cargo.toml", `[package] name = "a" version = "0.1.0" edition = "2021" [dependencies] b = { path = "../b" } `, ); writeVW( "crates/b/Cargo.toml", `[package] name = "b" version = "0.1.0" edition = "2021" `, ); }); afterAll(() => { rmSync(VW, { recursive: true, force: true }); }); test("virtual workspace: 2 crates, 1 edge, depth 2", () => { const r = computeRustGraphDepth(VW); expect(r.nodeCount).toBe(2); expect(r.edgeCount).toBe(1); expect(r.depth).toBe(2); }); });