syntaxai/tdd.md · main · src / a31_git_parse.test.ts
import { test, expect } from "bun:test";
import {
parseGitCommits,
parseLsTreeLine,
GIT_COMMIT_FORMAT,
} from "./a31_git_parse.ts";
const FS = "\x1f";
const RS = "\x1e";
const fakeCommit = (
sha: string,
parents: string,
msg: string,
ts = "2026-05-10T13:00:00+01:00",
): string =>
[sha, parents, "syntaxai", "[email protected]", ts, "syntaxai", "[email protected]", ts, msg].join(FS) + RS;
test("parses a single commit with one parent and short message", () => {
const raw = fakeCommit("abc123", "def456", "edit content/sama/skill.md\n");
const commits = parseGitCommits(raw);
expect(commits).toHaveLength(1);
const c = commits[0]!;
expect(c.sha).toBe("abc123");
expect(c.parents).toEqual(["def456"]);
expect(c.authorName).toBe("syntaxai");
expect(c.message).toBe("edit content/sama/skill.md");
});
test("parses multiple commits separated by RS", () => {
const raw =
fakeCommit("aaa", "bbb", "first") +
fakeCommit("bbb", "ccc", "second") +
fakeCommit("ccc", "", "root commit");
const commits = parseGitCommits(raw);
expect(commits.map((c) => c.sha)).toEqual(["aaa", "bbb", "ccc"]);
expect(commits[2]!.parents).toEqual([]);
});
test("preserves multi-line commit message body", () => {
const msg = "subject line\n\nbody line one\nbody line two\n";
const raw = fakeCommit("xyz", "par", msg);
const c = parseGitCommits(raw)[0]!;
expect(c.message).toBe("subject line\n\nbody line one\nbody line two");
});
test("merge commit has multiple parents", () => {
const raw = fakeCommit("merge1", "p1 p2 p3", "merge");
const c = parseGitCommits(raw)[0]!;
expect(c.parents).toEqual(["p1", "p2", "p3"]);
});
test("empty input yields empty array", () => {
expect(parseGitCommits("")).toEqual([]);
});
test("malformed record throws", () => {
expect(() => parseGitCommits("not enough fields here" + RS)).toThrow();
});
test("GIT_COMMIT_FORMAT round-trips through %x1e/%x1f hex escapes", () => {
// The format string passes \x1e and \x1f as %x1e / %x1f to git's
// printf-style placeholder language. This guards against accidental
// edits that break the round-trip.
expect(GIT_COMMIT_FORMAT).toContain("%x1f");
expect(GIT_COMMIT_FORMAT).toEndWith("%x1e");
});
test("parseLsTreeLine accepts a regular blob row", () => {
const r = parseLsTreeLine("100644 blob abc123def456\tcontent/sama/skill.md");
expect(r).toEqual({
mode: "100644",
type: "blob",
sha: "abc123def456",
path: "content/sama/skill.md",
});
});
test("parseLsTreeLine accepts a tree row", () => {
const r = parseLsTreeLine("040000 tree treesha\tcontent");
expect(r?.type).toBe("tree");
});
test("parseLsTreeLine returns null for blank or malformed input", () => {
expect(parseLsTreeLine("")).toBeNull();
expect(parseLsTreeLine("not even tab separated")).toBeNull();
expect(parseLsTreeLine("100644 weirdtype sha\tpath")).toBeNull();
});
test("parseLsTreeLine preserves paths with embedded spaces", () => {
const r = parseLsTreeLine("100644 blob abc\tcontent/with space/file.md");
expect(r?.path).toBe("content/with space/file.md");
});