syntaxai/tdd.md · main · src / c14_rust_graph_depth.test.ts

c14_rust_graph_depth.test.ts 200 lines · 5013 bytes raw
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<string, string>;
    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<string, string>;
    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);
  });
});