This repository has been archived on 2026-08-23. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
pi-web/src/server/workspaces/fileContentService.test.ts
T

71 lines
2.5 KiB
TypeScript

import { mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { readWorkspaceFile } from "./fileContentService.js";
const roots: string[] = [];
async function tempWorkspace(): Promise<string> {
const root = await mkdtemp(join(tmpdir(), "pi-web-file-content-"));
roots.push(root);
return root;
}
afterEach(async () => {
await Promise.all(roots.splice(0).map((root) => rm(root, { recursive: true, force: true })));
});
describe("readWorkspaceFile", () => {
it("reads text files with normalized paths and language metadata", async () => {
const root = await tempWorkspace();
await mkdir(join(root, "src"));
await writeFile(join(root, "src", "main.ts"), "const answer = 42;\n");
const file = await readWorkspaceFile(root, "./src//main.ts");
expect(file).toMatchObject({
path: "src/main.ts",
language: "typescript",
encoding: "utf8",
content: "const answer = 42;\n",
truncated: false,
binary: false,
});
expect(file.size).toBe(19);
expect(Date.parse(file.modifiedAt)).not.toBeNaN();
});
it("rejects missing paths, directories, traversal, and absolute paths", async () => {
const root = await tempWorkspace();
await mkdir(join(root, "dir"));
await expect(readWorkspaceFile(root, undefined)).rejects.toThrow("path query parameter is required");
await expect(readWorkspaceFile(root, "dir")).rejects.toThrow("Path is not a file");
await expect(readWorkspaceFile(root, "../secret.txt")).rejects.toThrow("Path traversal is not allowed");
await expect(readWorkspaceFile(root, "/etc/passwd")).rejects.toThrow("Absolute paths are not allowed");
});
it("detects binary files and omits binary content", async () => {
const root = await tempWorkspace();
await writeFile(join(root, "image.bin"), Buffer.from([0x66, 0x6f, 0x00, 0x6f]));
const file = await readWorkspaceFile(root, "image.bin");
expect(file).toMatchObject({ content: "", binary: true, truncated: false });
expect(file.size).toBe(4);
});
it("truncates large text files", async () => {
const root = await tempWorkspace();
await writeFile(join(root, "large.md"), "a".repeat(512 * 1024 + 7));
const file = await readWorkspaceFile(root, "large.md");
expect(file.language).toBe("markdown");
expect(file.content).toHaveLength(512 * 1024);
expect(file.truncated).toBe(true);
expect(file.binary).toBe(false);
});
});