// src/tools/file/write.test.ts // Copyright (C) 2025 DTP Technologies, LLC // All Rights Reserved import { describe, it, expect, beforeEach, afterEach } from "vitest"; import { FileWriteTool } from "./write.js"; import fs from "node:fs/promises"; import path from "node:path"; import { PROJECT_ROOT } from "../../config/env.js"; const tool = new FileWriteTool(); describe("FileWriteTool", () => { const testDir = path.join(PROJECT_ROOT, "test-temp-write"); const testFile = path.join(testDir, "test.txt"); beforeEach(async () => { await fs.mkdir(testDir, { recursive: true }); }); afterEach(async () => { await fs.rm(testDir, { recursive: true, force: true }); }); it("should have correct tool definition", () => { expect(tool.definition.function.name).toBe("file_write"); expect(tool.definition.function.description).toContain( "Create a new file or overwrite", ); const params = tool.definition.function.parameters as any; expect(params.required).toEqual(["path", "content"]); }); it("should reject empty path", async () => { const result = await tool.execute({} as any, { content: "test" }); expect(result).toContain("error"); expect(result).toContain("MISSING_PARAMETER"); }); it("should reject undefined content", async () => { const result = await tool.execute({} as any, { path: "test.txt" }); expect(result).toContain("error"); expect(result).toContain("MISSING_PARAMETER"); }); it("should reject path traversal attempts", async () => { const result = await tool.execute({} as any, { path: "../../../etc/passwd", content: "test", }); expect(result).toContain("error"); expect(result).toContain("SECURITY_VIOLATION"); }); it("should create new file and return plain text response", async () => { const result = await tool.execute({} as any, { path: "test-temp-write/test.txt", content: "Hello, World!", }); expect(result).not.toContain('"success"'); expect(result).toContain("PATH:"); expect(result).toContain("FILE OPERATION: write"); expect(result).toContain("CREATED: true"); expect(result).toContain("BYTES WRITTEN:"); expect(result).toContain("---"); expect(result).toContain("File written:"); }); it("should overwrite existing file and return plain text response", async () => { // Create file first await fs.writeFile(testFile, "original content"); const result = await tool.execute({} as any, { path: "test-temp-write/test.txt", content: "new content", }); expect(result).not.toContain('"success"'); expect(result).toContain("PATH:"); expect(result).toContain("FILE OPERATION: write"); expect(result).toContain("CREATED: false"); expect(result).toContain("BYTES WRITTEN:"); expect(result).toContain("---"); }); it("should create parent directories automatically", async () => { const nestedPath = "test-temp-write/nested/deep/file.txt"; const result = await tool.execute({} as any, { path: nestedPath, content: "nested content", }); expect(result).toContain("File written:"); const exists = await fs .access(path.join(PROJECT_ROOT, nestedPath)) .then(() => true) .catch(() => false); expect(exists).toBe(true); }); it("should return correct byte count", async () => { const content = "Hello, World!"; const result = await tool.execute({} as any, { path: "test-temp-write/bytecount.txt", content: content, }); const expectedBytes = Buffer.byteLength(content, "utf-8"); expect(result).toContain(`BYTES WRITTEN: ${expectedBytes}`); }); it("should handle multiline content", async () => { const content = "Line 1\nLine 2\nLine 3"; const result = await tool.execute({} as any, { path: "test-temp-write/multiline.txt", content: content, }); expect(result).toContain("File written:"); const written = await fs.readFile( path.join(PROJECT_ROOT, "test-temp-write/multiline.txt"), "utf-8", ); expect(written).toBe(content); }); it("should handle empty content", async () => { const result = await tool.execute({} as any, { path: "test-temp-write/empty.txt", content: "", }); expect(result).toContain("BYTES WRITTEN: 0"); const written = await fs.readFile( path.join(PROJECT_ROOT, "test-temp-write/empty.txt"), "utf-8", ); expect(written).toBe(""); }); it("should not return JSON format on success", async () => { const result = await tool.execute({} as any, { path: "test-temp-write/nojson.txt", content: "test", }); // Should not contain JSON structure expect(result).not.toMatch(/^\s*\{/); expect(result).not.toContain('"success":'); expect(result).not.toContain('"data":'); expect(result).not.toContain('"message":'); }); });