syntaxai/tdd.md · main · src / c14_go_graph_depth.test.ts
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 {
collectGoImports,
computeGoGraphDepth,
parseGoModulePath,
} from "./c14_go_graph_depth.ts";
const FIXTURE = mkdtempSync(resolve(tmpdir(), "tdd-md-go-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(() => {
writeFile(
"go.mod",
`module github.com/example/fixture
go 1.22
`,
);
// Three packages forming a chain entry → middle → leaf, plus
// some external imports we should NOT count.
writeFile(
"cmd/entry/main.go",
`package main
import (
"fmt"
"github.com/example/fixture/internal/middle"
"github.com/example/external/library"
)
func main() {
fmt.Println(middle.X)
_ = library.Y
}
`,
);
writeFile(
"internal/middle/middle.go",
`package middle
import (
"github.com/example/fixture/internal/leaf"
)
var X = leaf.Z
`,
);
writeFile(
"internal/leaf/leaf.go",
`package leaf
var Z = 1
`,
);
// A test file that should be excluded.
writeFile(
"internal/leaf/leaf_test.go",
`package leaf
import (
"testing"
"github.com/example/fixture/internal/middle"
)
func TestZ(t *testing.T) { _ = middle.X }
`,
);
// A vendored file that should also be skipped.
writeFile(
"vendor/some/lib.go",
`package some
import "github.com/example/fixture/cmd/entry"
var _ = entry.X
`,
);
});
afterAll(() => {
rmSync(FIXTURE, { recursive: true, force: true });
});
describe("parseGoModulePath", () => {
test("extracts the module path from a typical go.mod", () => {
expect(parseGoModulePath('module github.com/x/y\n\ngo 1.22\n'))
.toBe('github.com/x/y');
});
test("handles quoted module paths", () => {
expect(parseGoModulePath('module "github.com/x/y"\n'))
.toBe('github.com/x/y');
});
test("throws when the go.mod has no module directive", () => {
expect(() => parseGoModulePath('go 1.22\n')).toThrow(/module/);
});
});
describe("collectGoImports", () => {
test("single-line import", () => {
expect(collectGoImports('package x\n\nimport "fmt"\n')).toEqual(['fmt']);
});
test("block import", () => {
const imports = collectGoImports(`package x
import (
"fmt"
"strings"
"github.com/x/y"
)
`);
expect(imports).toEqual(['fmt', 'strings', 'github.com/x/y']);
});
test("aliased imports", () => {
const imports = collectGoImports(`package x
import (
myfmt "fmt"
_ "side-effect/pkg"
)
`);
expect(imports).toEqual(['fmt', 'side-effect/pkg']);
});
test("ignores commented-out imports", () => {
const imports = collectGoImports(`package x
// import "ignored"
import "fmt"
`);
expect(imports).toEqual(['fmt']);
});
});
describe("computeGoGraphDepth — end-to-end on fixture", () => {
test("entry → middle → leaf chain produces depth 3", () => {
const r = computeGoGraphDepth(FIXTURE);
expect(r.language).toBe('go');
expect(r.modulePath).toBe('github.com/example/fixture');
// Three intra-module package directories: cmd/entry,
// internal/middle, internal/leaf. (vendor/some excluded.)
expect(r.nodeCount).toBe(3);
// Two intra-module edges: cmd/entry → internal/middle,
// internal/middle → internal/leaf. (External and vendored
// edges excluded; the _test.go edge to middle excluded because
// _test.go files are skipped.)
expect(r.edgeCount).toBe(2);
expect(r.depth).toBe(3);
});
test("result echoes the modulePath so callers can audit", () => {
const r = computeGoGraphDepth(FIXTURE);
expect(r.modulePath).toBe('github.com/example/fixture');
});
test("re-running on the same tree produces identical numbers", () => {
const a = computeGoGraphDepth(FIXTURE);
const b = computeGoGraphDepth(FIXTURE);
expect(a).toEqual(b);
});
});