test / write.test.ts
import { promises as fs } from "fs";
import * as path from "path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { OUT_OF_SCOPE } from "../src/paths";
import { runWrite } from "../src/tools/write";
import { makeRoot } from "./helpers";
let root: string;
beforeEach(async () => {
root = await makeRoot();
});
afterEach(async () => {
await fs.rm(root, { recursive: true, force: true });
});
describe("runWrite", () => {
it("creates a file and reports bytes", async () => {
expect(await runWrite(root, { path: "a.txt", content: "hello" })).toBe("written 5 bytes to a.txt");
expect(await fs.readFile(path.join(root, "a.txt"), "utf8")).toBe("hello");
});
it("counts UTF-8 bytes, not characters", async () => {
expect(await runWrite(root, { path: "a.txt", content: "é" })).toBe("written 2 bytes to a.txt");
});
it("creates parent directories", async () => {
await runWrite(root, { path: "x/y/z.txt", content: "deep" });
expect(await fs.readFile(path.join(root, "x", "y", "z.txt"), "utf8")).toBe("deep");
});
it("overwrites an existing file", async () => {
await fs.writeFile(path.join(root, "a.txt"), "old content");
await runWrite(root, { path: "a.txt", content: "new" });
expect(await fs.readFile(path.join(root, "a.txt"), "utf8")).toBe("new");
});
it("leaves no temp files behind", async () => {
await runWrite(root, { path: "a.txt", content: "hello" });
expect(await fs.readdir(root)).toEqual(["a.txt"]);
});
it("rejects out-of-scope paths and writes nothing", async () => {
expect(await runWrite(root, { path: "../evil.txt", content: "x" })).toBe(OUT_OF_SCOPE);
await expect(fs.access(path.join(root, "..", "evil.txt"))).rejects.toThrow();
});
it("errors when the target is a directory", async () => {
await fs.mkdir(path.join(root, "d"));
expect(await runWrite(root, { path: "d", content: "x" })).toBe("Error: is a directory, not a file: d");
});
it("errors when a parent path component is a file", async () => {
await fs.writeFile(path.join(root, "f"), "x");
expect(await runWrite(root, { path: "f/child.txt", content: "x" })).toMatch(/^Error: /);
});
});
test / write.test.ts
import { promises as fs } from "fs";
import * as path from "path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { OUT_OF_SCOPE } from "../src/paths";
import { runWrite } from "../src/tools/write";
import { makeRoot } from "./helpers";
let root: string;
beforeEach(async () => {
root = await makeRoot();
});
afterEach(async () => {
await fs.rm(root, { recursive: true, force: true });
});
describe("runWrite", () => {
it("creates a file and reports bytes", async () => {
expect(await runWrite(root, { path: "a.txt", content: "hello" })).toBe("written 5 bytes to a.txt");
expect(await fs.readFile(path.join(root, "a.txt"), "utf8")).toBe("hello");
});
it("counts UTF-8 bytes, not characters", async () => {
expect(await runWrite(root, { path: "a.txt", content: "é" })).toBe("written 2 bytes to a.txt");
});
it("creates parent directories", async () => {
await runWrite(root, { path: "x/y/z.txt", content: "deep" });
expect(await fs.readFile(path.join(root, "x", "y", "z.txt"), "utf8")).toBe("deep");
});
it("overwrites an existing file", async () => {
await fs.writeFile(path.join(root, "a.txt"), "old content");
await runWrite(root, { path: "a.txt", content: "new" });
expect(await fs.readFile(path.join(root, "a.txt"), "utf8")).toBe("new");
});
it("leaves no temp files behind", async () => {
await runWrite(root, { path: "a.txt", content: "hello" });
expect(await fs.readdir(root)).toEqual(["a.txt"]);
});
it("rejects out-of-scope paths and writes nothing", async () => {
expect(await runWrite(root, { path: "../evil.txt", content: "x" })).toBe(OUT_OF_SCOPE);
await expect(fs.access(path.join(root, "..", "evil.txt"))).rejects.toThrow();
});
it("errors when the target is a directory", async () => {
await fs.mkdir(path.join(root, "d"));
expect(await runWrite(root, { path: "d", content: "x" })).toBe("Error: is a directory, not a file: d");
});
it("errors when a parent path component is a file", async () => {
await fs.writeFile(path.join(root, "f"), "x");
expect(await runWrite(root, { path: "f/child.txt", content: "x" })).toMatch(/^Error: /);
});
});