summaryrefslogtreecommitdiffhomepage
path: root/packages/tool-write-file/src/write-file.test.ts
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-26 22:03:19 +0900
committerAdam Malczewski <[email protected]>2026-06-26 22:23:39 +0900
commit727c98c9dae516a2070eb950410314380a20c974 (patch)
tree52aa1022c54f11770be7e4e2a324f0a8b8b8deec /packages/tool-write-file/src/write-file.test.ts
parente59dc11f63b1df51142259bb2c406af8c9c8c2bb (diff)
downloaddispatch-727c98c9dae516a2070eb950410314380a20c974.tar.gz
dispatch-727c98c9dae516a2070eb950410314380a20c974.zip
style: switch from tabs to 2-space indentation
Diffstat (limited to 'packages/tool-write-file/src/write-file.test.ts')
-rw-r--r--packages/tool-write-file/src/write-file.test.ts420
1 files changed, 210 insertions, 210 deletions
diff --git a/packages/tool-write-file/src/write-file.test.ts b/packages/tool-write-file/src/write-file.test.ts
index d157eb2..5999291 100644
--- a/packages/tool-write-file/src/write-file.test.ts
+++ b/packages/tool-write-file/src/write-file.test.ts
@@ -7,17 +7,17 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { createWriteFileTool, decideOverwrite, validateArgs } from "./write-file.js";
function stubCtx(overrides?: Partial<ToolExecuteContext>): ToolExecuteContext {
- return {
- toolCallId: "test-call-1",
- onOutput: () => {},
- signal: AbortSignal.timeout(5000),
- log: createLogger(
- { extensionId: "test" },
- { emit: () => {} },
- { now: () => 0, newId: () => "id" },
- ),
- ...overrides,
- };
+ return {
+ toolCallId: "test-call-1",
+ onOutput: () => {},
+ signal: AbortSignal.timeout(5000),
+ log: createLogger(
+ { extensionId: "test" },
+ { emit: () => {} },
+ { now: () => 0, newId: () => "id" },
+ ),
+ ...overrides,
+ };
}
/**
@@ -26,220 +26,220 @@ function stubCtx(overrides?: Partial<ToolExecuteContext>): ToolExecuteContext {
* real fs edge is exercised, matching the constitution's strict-core rule.
*/
function makeTool(workdir: string) {
- return createWriteFileTool({ resolveBackend: () => localExecBackend, workdir });
+ return createWriteFileTool({ resolveBackend: () => localExecBackend, workdir });
}
let workdir: string;
beforeEach(async () => {
- workdir = await mkdtemp(join(tmpdir(), "tool-write-file-test-"));
+ workdir = await mkdtemp(join(tmpdir(), "tool-write-file-test-"));
});
afterEach(async () => {
- await rm(workdir, { recursive: true, force: true });
+ await rm(workdir, { recursive: true, force: true });
});
describe("decideOverwrite", () => {
- it("returns create when file absent and overwrite is false", () => {
- expect(decideOverwrite(false, false)).toBe("create");
- });
-
- it("returns create when file absent and overwrite is false (default)", () => {
- expect(decideOverwrite(false, false)).toBe("create");
- });
-
- it("returns error when file exists and overwrite is false", () => {
- const result = decideOverwrite(true, false);
- expect(typeof result).toBe("object");
- if (typeof result === "object") {
- expect(result.error).toContain("already exists");
- }
- });
-
- it("returns overwrite when file exists and overwrite is true", () => {
- expect(decideOverwrite(true, true)).toBe("overwrite");
- });
-
- it("returns error when file absent and overwrite is true", () => {
- const result = decideOverwrite(false, true);
- expect(typeof result).toBe("object");
- if (typeof result === "object") {
- expect(result.error).toContain("does not exist");
- }
- });
-
- it("covers all four rows of the truth table", () => {
- expect(decideOverwrite(false, false)).toBe("create");
- expect(decideOverwrite(true, false)).toEqual(
- expect.objectContaining({ error: expect.any(String) }),
- );
- expect(decideOverwrite(true, true)).toBe("overwrite");
- expect(decideOverwrite(false, true)).toEqual(
- expect.objectContaining({ error: expect.any(String) }),
- );
- });
+ it("returns create when file absent and overwrite is false", () => {
+ expect(decideOverwrite(false, false)).toBe("create");
+ });
+
+ it("returns create when file absent and overwrite is false (default)", () => {
+ expect(decideOverwrite(false, false)).toBe("create");
+ });
+
+ it("returns error when file exists and overwrite is false", () => {
+ const result = decideOverwrite(true, false);
+ expect(typeof result).toBe("object");
+ if (typeof result === "object") {
+ expect(result.error).toContain("already exists");
+ }
+ });
+
+ it("returns overwrite when file exists and overwrite is true", () => {
+ expect(decideOverwrite(true, true)).toBe("overwrite");
+ });
+
+ it("returns error when file absent and overwrite is true", () => {
+ const result = decideOverwrite(false, true);
+ expect(typeof result).toBe("object");
+ if (typeof result === "object") {
+ expect(result.error).toContain("does not exist");
+ }
+ });
+
+ it("covers all four rows of the truth table", () => {
+ expect(decideOverwrite(false, false)).toBe("create");
+ expect(decideOverwrite(true, false)).toEqual(
+ expect.objectContaining({ error: expect.any(String) }),
+ );
+ expect(decideOverwrite(true, true)).toBe("overwrite");
+ expect(decideOverwrite(false, true)).toEqual(
+ expect.objectContaining({ error: expect.any(String) }),
+ );
+ });
});
describe("validateArgs", () => {
- it("returns validated args for valid input", () => {
- const result = validateArgs({ path: "foo.txt", content: "hello" });
- expect(result).toEqual({ path: "foo.txt", content: "hello", overwrite: false });
- });
-
- it("parses overwrite as true", () => {
- const result = validateArgs({ path: "foo.txt", content: "x", overwrite: true });
- expect(result).toEqual({ path: "foo.txt", content: "x", overwrite: true });
- });
-
- it("defaults overwrite to false", () => {
- const result = validateArgs({ path: "foo.txt", content: "x" });
- expect(result).toEqual({ path: "foo.txt", content: "x", overwrite: false });
- });
-
- it("accepts empty string content", () => {
- const result = validateArgs({ path: "foo.txt", content: "" });
- expect(result).toEqual({ path: "foo.txt", content: "", overwrite: false });
- });
-
- it("returns error for null args", () => {
- expect(validateArgs(null)).toHaveProperty("error");
- });
-
- it("returns error for missing path", () => {
- expect(validateArgs({ content: "x" })).toHaveProperty("error");
- });
-
- it("returns error for missing content", () => {
- expect(validateArgs({ path: "foo.txt" })).toHaveProperty("error");
- });
-
- it("returns error for non-string content", () => {
- expect(validateArgs({ path: "foo.txt", content: 123 })).toHaveProperty("error");
- });
-
- it("returns error for non-boolean overwrite", () => {
- expect(validateArgs({ path: "foo.txt", content: "x", overwrite: "yes" })).toHaveProperty(
- "error",
- );
- });
+ it("returns validated args for valid input", () => {
+ const result = validateArgs({ path: "foo.txt", content: "hello" });
+ expect(result).toEqual({ path: "foo.txt", content: "hello", overwrite: false });
+ });
+
+ it("parses overwrite as true", () => {
+ const result = validateArgs({ path: "foo.txt", content: "x", overwrite: true });
+ expect(result).toEqual({ path: "foo.txt", content: "x", overwrite: true });
+ });
+
+ it("defaults overwrite to false", () => {
+ const result = validateArgs({ path: "foo.txt", content: "x" });
+ expect(result).toEqual({ path: "foo.txt", content: "x", overwrite: false });
+ });
+
+ it("accepts empty string content", () => {
+ const result = validateArgs({ path: "foo.txt", content: "" });
+ expect(result).toEqual({ path: "foo.txt", content: "", overwrite: false });
+ });
+
+ it("returns error for null args", () => {
+ expect(validateArgs(null)).toHaveProperty("error");
+ });
+
+ it("returns error for missing path", () => {
+ expect(validateArgs({ content: "x" })).toHaveProperty("error");
+ });
+
+ it("returns error for missing content", () => {
+ expect(validateArgs({ path: "foo.txt" })).toHaveProperty("error");
+ });
+
+ it("returns error for non-string content", () => {
+ expect(validateArgs({ path: "foo.txt", content: 123 })).toHaveProperty("error");
+ });
+
+ it("returns error for non-boolean overwrite", () => {
+ expect(validateArgs({ path: "foo.txt", content: "x", overwrite: "yes" })).toHaveProperty(
+ "error",
+ );
+ });
});
describe("createWriteFileTool", () => {
- it("creates a new file when overwrite is unset and the file is absent", async () => {
- const tool = makeTool(workdir);
- const result = await tool.execute({ path: "new-file.txt", content: "hello world" }, stubCtx());
-
- expect(result.isError).toBeUndefined();
- expect(result.content).toContain("Created");
- const written = await readFile(join(workdir, "new-file.txt"), "utf8");
- expect(written).toBe("hello world");
- });
-
- it("errors when the file exists and overwrite is unset", async () => {
- await writeFile(join(workdir, "existing.txt"), "old content", "utf8");
-
- const tool = makeTool(workdir);
- const result = await tool.execute({ path: "existing.txt", content: "new content" }, stubCtx());
-
- expect(result.isError).toBe(true);
- expect(result.content).toContain("already exists");
- expect(result.content).toContain("overwrite");
- const unchanged = await readFile(join(workdir, "existing.txt"), "utf8");
- expect(unchanged).toBe("old content");
- });
-
- it("overwrites an existing file when overwrite is true", async () => {
- await writeFile(join(workdir, "existing.txt"), "old content", "utf8");
-
- const tool = makeTool(workdir);
- const result = await tool.execute(
- { path: "existing.txt", content: "new content", overwrite: true },
- stubCtx(),
- );
-
- expect(result.isError).toBeUndefined();
- expect(result.content).toContain("Overwrote");
- const written = await readFile(join(workdir, "existing.txt"), "utf8");
- expect(written).toBe("new content");
- });
-
- it("errors when overwrite is true but the file is absent", async () => {
- const tool = makeTool(workdir);
- const result = await tool.execute(
- { path: "nonexistent.txt", content: "data", overwrite: true },
- stubCtx(),
- );
-
- expect(result.isError).toBe(true);
- expect(result.content).toContain("does not exist");
- });
-
- it("errors when the parent directory does not exist", async () => {
- const tool = makeTool(workdir);
- const result = await tool.execute({ path: "no/such/dir/file.txt", content: "data" }, stubCtx());
-
- expect(result.isError).toBe(true);
- expect(result.content).toContain("Error");
- });
-
- it("concurrencySafe is false", () => {
- const tool = makeTool(workdir);
- expect(tool.concurrencySafe).toBe(false);
- });
-
- it("has correct name and parameters shape", () => {
- const tool = makeTool(workdir);
- expect(tool.name).toBe("write_file");
- expect(tool.parameters.type).toBe("object");
- expect(tool.parameters.required).toEqual(["path", "content"]);
- expect(tool.parameters.properties?.path?.type).toBe("string");
- expect(tool.parameters.properties?.content?.type).toBe("string");
- expect(tool.parameters.properties?.overwrite?.type).toBe("boolean");
- });
-
- it("never throws on bad input (always returns ToolResult)", async () => {
- const tool = makeTool(workdir);
- const inputs = [null, undefined, 42, "string", {}, { path: "" }, { path: 123 }];
- for (const input of inputs) {
- const result = await tool.execute(input, stubCtx());
- expect(result).toHaveProperty("content");
- expect(typeof result.content).toBe("string");
- }
- });
-
- it("respects ctx.cwd over baked workdir", async () => {
- const ctxDir = await mkdtemp(join(tmpdir(), "ctx-cwd-test-"));
- try {
- const tool = makeTool(workdir);
- const result = await tool.execute(
- { path: "ctx-file.txt", content: "from ctx" },
- stubCtx({ cwd: ctxDir }),
- );
-
- expect(result.isError).toBeUndefined();
- const written = await readFile(join(ctxDir, "ctx-file.txt"), "utf8");
- expect(written).toBe("from ctx");
- } finally {
- await rm(ctxDir, { recursive: true, force: true });
- }
- });
-
- it("writes empty content", async () => {
- const tool = makeTool(workdir);
- const result = await tool.execute({ path: "empty.txt", content: "" }, stubCtx());
-
- expect(result.isError).toBeUndefined();
- const written = await readFile(join(workdir, "empty.txt"), "utf8");
- expect(written).toBe("");
- });
-
- it("writes content in subdirectory that exists", async () => {
- await mkdir(join(workdir, "sub"));
- const tool = makeTool(workdir);
- const result = await tool.execute({ path: "sub/file.txt", content: "nested" }, stubCtx());
-
- expect(result.isError).toBeUndefined();
- const written = await readFile(join(workdir, "sub", "file.txt"), "utf8");
- expect(written).toBe("nested");
- });
+ it("creates a new file when overwrite is unset and the file is absent", async () => {
+ const tool = makeTool(workdir);
+ const result = await tool.execute({ path: "new-file.txt", content: "hello world" }, stubCtx());
+
+ expect(result.isError).toBeUndefined();
+ expect(result.content).toContain("Created");
+ const written = await readFile(join(workdir, "new-file.txt"), "utf8");
+ expect(written).toBe("hello world");
+ });
+
+ it("errors when the file exists and overwrite is unset", async () => {
+ await writeFile(join(workdir, "existing.txt"), "old content", "utf8");
+
+ const tool = makeTool(workdir);
+ const result = await tool.execute({ path: "existing.txt", content: "new content" }, stubCtx());
+
+ expect(result.isError).toBe(true);
+ expect(result.content).toContain("already exists");
+ expect(result.content).toContain("overwrite");
+ const unchanged = await readFile(join(workdir, "existing.txt"), "utf8");
+ expect(unchanged).toBe("old content");
+ });
+
+ it("overwrites an existing file when overwrite is true", async () => {
+ await writeFile(join(workdir, "existing.txt"), "old content", "utf8");
+
+ const tool = makeTool(workdir);
+ const result = await tool.execute(
+ { path: "existing.txt", content: "new content", overwrite: true },
+ stubCtx(),
+ );
+
+ expect(result.isError).toBeUndefined();
+ expect(result.content).toContain("Overwrote");
+ const written = await readFile(join(workdir, "existing.txt"), "utf8");
+ expect(written).toBe("new content");
+ });
+
+ it("errors when overwrite is true but the file is absent", async () => {
+ const tool = makeTool(workdir);
+ const result = await tool.execute(
+ { path: "nonexistent.txt", content: "data", overwrite: true },
+ stubCtx(),
+ );
+
+ expect(result.isError).toBe(true);
+ expect(result.content).toContain("does not exist");
+ });
+
+ it("errors when the parent directory does not exist", async () => {
+ const tool = makeTool(workdir);
+ const result = await tool.execute({ path: "no/such/dir/file.txt", content: "data" }, stubCtx());
+
+ expect(result.isError).toBe(true);
+ expect(result.content).toContain("Error");
+ });
+
+ it("concurrencySafe is false", () => {
+ const tool = makeTool(workdir);
+ expect(tool.concurrencySafe).toBe(false);
+ });
+
+ it("has correct name and parameters shape", () => {
+ const tool = makeTool(workdir);
+ expect(tool.name).toBe("write_file");
+ expect(tool.parameters.type).toBe("object");
+ expect(tool.parameters.required).toEqual(["path", "content"]);
+ expect(tool.parameters.properties?.path?.type).toBe("string");
+ expect(tool.parameters.properties?.content?.type).toBe("string");
+ expect(tool.parameters.properties?.overwrite?.type).toBe("boolean");
+ });
+
+ it("never throws on bad input (always returns ToolResult)", async () => {
+ const tool = makeTool(workdir);
+ const inputs = [null, undefined, 42, "string", {}, { path: "" }, { path: 123 }];
+ for (const input of inputs) {
+ const result = await tool.execute(input, stubCtx());
+ expect(result).toHaveProperty("content");
+ expect(typeof result.content).toBe("string");
+ }
+ });
+
+ it("respects ctx.cwd over baked workdir", async () => {
+ const ctxDir = await mkdtemp(join(tmpdir(), "ctx-cwd-test-"));
+ try {
+ const tool = makeTool(workdir);
+ const result = await tool.execute(
+ { path: "ctx-file.txt", content: "from ctx" },
+ stubCtx({ cwd: ctxDir }),
+ );
+
+ expect(result.isError).toBeUndefined();
+ const written = await readFile(join(ctxDir, "ctx-file.txt"), "utf8");
+ expect(written).toBe("from ctx");
+ } finally {
+ await rm(ctxDir, { recursive: true, force: true });
+ }
+ });
+
+ it("writes empty content", async () => {
+ const tool = makeTool(workdir);
+ const result = await tool.execute({ path: "empty.txt", content: "" }, stubCtx());
+
+ expect(result.isError).toBeUndefined();
+ const written = await readFile(join(workdir, "empty.txt"), "utf8");
+ expect(written).toBe("");
+ });
+
+ it("writes content in subdirectory that exists", async () => {
+ await mkdir(join(workdir, "sub"));
+ const tool = makeTool(workdir);
+ const result = await tool.execute({ path: "sub/file.txt", content: "nested" }, stubCtx());
+
+ expect(result.isError).toBeUndefined();
+ const written = await readFile(join(workdir, "sub", "file.txt"), "utf8");
+ expect(written).toBe("nested");
+ });
});