import { Database } from "bun:sqlite"; import { afterEach, beforeEach, describe, expect, test } from "bun:test"; import { backfillProjectRootGitRemotes } from "../backfill-git-remotes"; let sqlite: Database; beforeEach(() => { sqlite = new Database(":memory:"); sqlite.exec(` CREATE TABLE project_roots ( id TEXT PRIMARY KEY, path TEXT NOT NULL, git_remote TEXT ); `); }); afterEach(() => { sqlite.close(); }); function insert(id: string, gitRemote: string | null): void { sqlite .prepare( "INSERT INTO project_roots (id, path, git_remote) VALUES (?, ?, ?)", ) .run(id, `/code/${id}`, gitRemote); } function remoteOf(id: string): string | null { const row = sqlite .prepare("SELECT git_remote AS gitRemote FROM project_roots WHERE id = ?") .get(id) as { gitRemote: string | null }; return row.gitRemote; } describe("backfillProjectRootGitRemotes", () => { test("normalizes raw https and scp remotes in place", () => { insert("https", "https://github.com/b-open-io/a2b.git"); insert("scp", "git@github.com:Owner/Repo.git"); insert("trailing", "https://GitHub.com/Owner/Repo/"); const changed = backfillProjectRootGitRemotes(sqlite); expect(changed).toBe(3); expect(remoteOf("https")).toBe("github.com/b-open-io/a2b"); expect(remoteOf("scp")).toBe("github.com/owner/repo"); expect(remoteOf("trailing")).toBe("github.com/owner/repo"); }); test("leaves already-normalized and null remotes untouched", () => { insert("canonical", "github.com/owner/repo"); insert("empty", null); const changed = backfillProjectRootGitRemotes(sqlite); expect(changed).toBe(0); expect(remoteOf("canonical")).toBe("github.com/owner/repo"); expect(remoteOf("empty")).toBeNull(); }); test("is idempotent — a second pass rewrites nothing", () => { insert("raw", "https://github.com/b-open-io/a2b.git"); expect(backfillProjectRootGitRemotes(sqlite)).toBe(1); expect(backfillProjectRootGitRemotes(sqlite)).toBe(0); expect(remoteOf("raw")).toBe("github.com/b-open-io/a2b"); }); });