- Update executor, triage, and merger prompt strings to identify the product as "fn" - Align branch/worktree documentation examples with fusion/fn-* naming conventions - Rename dashboard websocket attachment guard from __kbWebSocketsAttached to __fnWebSocketsAttached - Refresh engine tests, dashboard utility comments, and TUI header text to remove stale kb wording
92 lines
3.1 KiB
TypeScript
92 lines
3.1 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { tmpdir } from "node:os";
|
|
import { generateWorktreeName, ADJECTIVES, NOUNS } from "./worktree-names.js";
|
|
|
|
describe("generateWorktreeName", () => {
|
|
let tempDir: string;
|
|
|
|
beforeEach(() => {
|
|
tempDir = mkdtempSync(join(tmpdir(), "fn-wt-test-"));
|
|
});
|
|
|
|
afterEach(() => {
|
|
rmSync(tempDir, { recursive: true, force: true });
|
|
});
|
|
|
|
it("returns a name matching adjective-noun pattern", () => {
|
|
const name = generateWorktreeName(tempDir);
|
|
expect(name).toMatch(/^[a-z]+-[a-z]+$/);
|
|
});
|
|
|
|
it("returns different names on subsequent calls (not deterministic)", () => {
|
|
// Generate several names — at least some should differ
|
|
const names = new Set<string>();
|
|
for (let i = 0; i < 20; i++) {
|
|
names.add(generateWorktreeName(tempDir));
|
|
}
|
|
// With 2500 combinations and 20 draws, we'd expect multiple unique names
|
|
expect(names.size).toBeGreaterThan(1);
|
|
});
|
|
|
|
it("avoids collision with existing .worktrees/ directories", () => {
|
|
// Create .worktrees dir with a known name
|
|
const worktreesDir = join(tempDir, ".worktrees");
|
|
mkdirSync(worktreesDir, { recursive: true });
|
|
|
|
// We need to force a collision — mock Math.random to always pick the same words
|
|
const originalRandom = Math.random;
|
|
Math.random = () => 0; // Will always pick first adjective and first noun
|
|
try {
|
|
// First call: should get the base name (e.g., "amber-badger")
|
|
const firstName = generateWorktreeName(tempDir);
|
|
expect(firstName).toMatch(/^[a-z]+-[a-z]+$/);
|
|
expect(firstName).not.toMatch(/-\d+$/); // no suffix
|
|
|
|
// Create that directory to simulate collision
|
|
mkdirSync(join(worktreesDir, firstName));
|
|
|
|
// Second call: should get a suffixed name
|
|
const secondName = generateWorktreeName(tempDir);
|
|
expect(secondName).toBe(`${firstName}-2`);
|
|
|
|
// Create that too
|
|
mkdirSync(join(worktreesDir, secondName));
|
|
|
|
// Third call: should get -3
|
|
const thirdName = generateWorktreeName(tempDir);
|
|
expect(thirdName).toBe(`${firstName}-3`);
|
|
} finally {
|
|
Math.random = originalRandom;
|
|
}
|
|
});
|
|
|
|
it("works when .worktrees/ directory does not exist", () => {
|
|
// tempDir has no .worktrees/ subdirectory
|
|
const name = generateWorktreeName(tempDir);
|
|
expect(name).toMatch(/^[a-z]+-[a-z]+$/);
|
|
});
|
|
|
|
it("ADJECTIVES and NOUNS share no common elements", () => {
|
|
const overlap = ADJECTIVES.filter((w) => NOUNS.includes(w));
|
|
expect(overlap).toEqual([]);
|
|
});
|
|
|
|
it("ADJECTIVES and NOUNS each have exactly 50 entries", () => {
|
|
expect(ADJECTIVES).toHaveLength(50);
|
|
expect(NOUNS).toHaveLength(50);
|
|
});
|
|
|
|
it("never generates a tautological name (adjective === noun)", () => {
|
|
const names: string[] = [];
|
|
for (let i = 0; i < 250; i++) {
|
|
names.push(generateWorktreeName(tempDir));
|
|
}
|
|
for (const name of names) {
|
|
const parts = name.split("-");
|
|
expect(parts[0]).not.toBe(parts[1]);
|
|
}
|
|
});
|
|
});
|