import { afterAll, describe, expect, test } from "bun:test"; import { mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { discoverProjects, isProjectDir } from "../src/core/discover.ts"; // Disk-backed scratch: /tmp is tmpfs on the dev box, and these are tiny, but // the habit matters. const root = mkdtempSync(join(tmpdir(), "sl0ppi-discover-")); afterAll(() => rmSync(root, { recursive: true, force: true })); function project(rel: string): void { mkdirSync(join(root, rel, ".sl0ppi"), { recursive: true }); writeFileSync(join(root, rel, ".sl0ppi", "layout.kdl"), "pane\n"); } function plainDir(rel: string): void { mkdirSync(join(root, rel), { recursive: true }); } project("beta"); project("alpha"); plainDir("not-a-project"); plainDir(".hidden-dir"); mkdirSync(join(root, ".hidden-dir", ".sl0ppi"), { recursive: true }); project("group/nested"); // depth 2 writeFileSync(join(root, "a-file"), ""); symlinkSync(join(root, "alpha"), join(root, "linked")); symlinkSync(join(root, "nowhere"), join(root, "broken-link")); describe("discoverProjects", () => { test("finds directories carrying the .sl0ppi marker, alphabetically", () => { expect(discoverProjects(root)).toEqual(["alpha", "beta", "linked"]); }); test("ignores directories without the marker", () => { expect(discoverProjects(root)).not.toContain("not-a-project"); }); test("ignores dotfiles even when they carry a marker", () => { expect(discoverProjects(root)).not.toContain(".hidden-dir"); }); test("is depth-1 by default", () => { expect(discoverProjects(root)).not.toContain("group/nested"); }); test("finds nested projects when asked", () => { expect(discoverProjects(root, { depth: 2 })).toContain("group/nested"); }); test("follows symlinked project dirs but survives broken ones", () => { const found = discoverProjects(root); expect(found).toContain("linked"); expect(found).not.toContain("broken-link"); }); test("returns empty for a missing root instead of throwing", () => { expect(discoverProjects(join(root, "does-not-exist"))).toEqual([]); }); }); describe("isProjectDir", () => { test("requires the marker to be a directory", () => { expect(isProjectDir(join(root, "alpha"))).toBe(true); expect(isProjectDir(join(root, "not-a-project"))).toBe(false); expect(isProjectDir(join(root, "nope"))).toBe(false); }); });