mirror of https://github.com/garrytan/gstack.git
126 lines
4.4 KiB
TypeScript
126 lines
4.4 KiB
TypeScript
import { describe, test, expect, beforeEach, afterEach } from "bun:test";
|
|
import fs from "fs";
|
|
import os from "os";
|
|
import path from "path";
|
|
import {
|
|
planRoundArtifacts,
|
|
resolveImagePaths,
|
|
} from "../src/cli";
|
|
|
|
const PNG_BYTES = Buffer.from(
|
|
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkAAIAAAoAAv/lxKUAAAAASUVORK5CYII=",
|
|
"base64",
|
|
);
|
|
|
|
function writePng(filePath: string): void {
|
|
fs.writeFileSync(filePath, PNG_BYTES);
|
|
}
|
|
|
|
function writeManifest(tmpDir: string, entries: Record<string, any[]>): void {
|
|
fs.writeFileSync(
|
|
path.join(tmpDir, ".gstack-design-rounds.json"),
|
|
JSON.stringify(entries, null, 2),
|
|
);
|
|
}
|
|
|
|
describe("plan-design-review round variant preservation", () => {
|
|
let tmpDir: string;
|
|
|
|
beforeEach(() => {
|
|
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "variant-preservation-"));
|
|
});
|
|
|
|
afterEach(() => {
|
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
});
|
|
|
|
test("recommended round allocates sequence-stable suffixed paths", () => {
|
|
const alias = path.join(tmpDir, "variant-recommended.png");
|
|
const first = planRoundArtifacts(alias);
|
|
|
|
expect(first?.primaryOutput).toBe(path.join(tmpDir, "variant-recommended-A.png"));
|
|
expect(first?.aliasOutput).toBe(alias);
|
|
|
|
writeManifest(tmpDir, {
|
|
[path.join(tmpDir, "variant-recommended")]: [
|
|
{ label: "A", path: first!.primaryOutput, success: true },
|
|
],
|
|
});
|
|
|
|
const second = planRoundArtifacts(alias);
|
|
expect(second?.primaryOutput).toBe(path.join(tmpDir, "variant-recommended-B.png"));
|
|
});
|
|
|
|
test("recommended round alias expands to every successful generated candidate", async () => {
|
|
const alias = path.join(tmpDir, "variant-recommended.png");
|
|
const variantA = path.join(tmpDir, "variant-recommended-A.png");
|
|
const variantB = path.join(tmpDir, "variant-recommended-B.png");
|
|
writePng(variantA);
|
|
writePng(variantB);
|
|
writePng(alias);
|
|
writeManifest(tmpDir, {
|
|
[path.join(tmpDir, "variant-recommended")]: [
|
|
{ label: "A", path: variantA, success: true },
|
|
{ label: "B", path: variantB, success: true },
|
|
],
|
|
});
|
|
|
|
await expect(resolveImagePaths(alias)).resolves.toEqual([variantA, variantB]);
|
|
});
|
|
|
|
test("iteration round discovers A/B/C candidates without collapsing onto the alias", async () => {
|
|
const alias = path.join(tmpDir, "variant-iteration-01.png");
|
|
const variantA = path.join(tmpDir, "variant-iteration-01-A.png");
|
|
const variantB = path.join(tmpDir, "variant-iteration-01-B.png");
|
|
const variantC = path.join(tmpDir, "variant-iteration-01-C.png");
|
|
writePng(variantA);
|
|
writePng(variantB);
|
|
writePng(variantC);
|
|
writePng(alias);
|
|
|
|
await expect(resolveImagePaths(alias)).resolves.toEqual([variantA, variantB, variantC]);
|
|
});
|
|
|
|
test("single recommended generation preserves the suffixed candidate and ignores alias copy", async () => {
|
|
const alias = path.join(tmpDir, "variant-recommended.png");
|
|
const variantA = path.join(tmpDir, "variant-recommended-A.png");
|
|
writePng(variantA);
|
|
writePng(alias);
|
|
writeManifest(tmpDir, {
|
|
[path.join(tmpDir, "variant-recommended")]: [
|
|
{ label: "A", path: variantA, success: true },
|
|
],
|
|
});
|
|
|
|
await expect(resolveImagePaths(alias)).resolves.toEqual([variantA]);
|
|
});
|
|
|
|
test("failed sibling leaves successful candidate in place and reports missing index", async () => {
|
|
const alias = path.join(tmpDir, "variant-recommended.png");
|
|
const variantA = path.join(tmpDir, "variant-recommended-A.png");
|
|
const variantB = path.join(tmpDir, "variant-recommended-B.png");
|
|
writePng(variantA);
|
|
writeManifest(tmpDir, {
|
|
[path.join(tmpDir, "variant-recommended")]: [
|
|
{ label: "A", path: variantA, success: true },
|
|
{ label: "B", path: variantB, success: false, error: "API error" },
|
|
],
|
|
});
|
|
|
|
await expect(resolveImagePaths(alias)).rejects.toThrow("variant-recommended-B.png");
|
|
expect(fs.existsSync(variantA)).toBe(true);
|
|
});
|
|
|
|
test("initial 3-option board paths are unchanged", async () => {
|
|
const variantA = path.join(tmpDir, "variant-A.png");
|
|
const variantB = path.join(tmpDir, "variant-B.png");
|
|
const variantC = path.join(tmpDir, "variant-C.png");
|
|
writePng(variantA);
|
|
writePng(variantB);
|
|
writePng(variantC);
|
|
|
|
const input = `${variantA},${variantB},${variantC}`;
|
|
await expect(resolveImagePaths(input)).resolves.toEqual([variantA, variantB, variantC]);
|
|
});
|
|
});
|