test/scripts/read-json.test.ts
Rama main · réplica de lectura del repositorio original.
import { join } from "node:path";
import { expect } from "@std/expect";
import { describe, it as test } from "@std/testing/bdd";
import * as v from "valibot";
import {
readJsonOrNull,
readJsonOrThrow,
writeJsonFile,
} from "#scripts/read-json.ts";
import { withTempDir } from "#test-utils/files.ts";
const NoteSchema = v.object({ note: v.string() });
/** Write `text` to a file in `folder` and read it back through the schema. */
const readBack = (folder: string, text: string) => {
const path = join(folder, "note.json");
Deno.writeTextFileSync(path, text);
return readJsonOrNull(path, NoteSchema);
};
describe("reading a JSON file that may not be there", () => {
test("gives back what the file holds", async () => {
await withTempDir(async (folder) => {
expect(await readBack(folder, '{ "note": "hello" }')).toEqual({
note: "hello",
});
});
});
test("answers nothing for a file that is not there", async () => {
await withTempDir(async (folder) => {
expect(
await readJsonOrNull(join(folder, "missing.json"), NoteSchema),
).toBe(null);
});
});
test("answers nothing for text that was left half written", async () => {
await withTempDir(async (folder) => {
expect(await readBack(folder, '{ "note": "hel')).toBeNull();
});
});
test("answers nothing for whole text of the wrong shape", async () => {
await withTempDir(async (folder) => {
expect(await readBack(folder, '{ "other": 1 }')).toBeNull();
});
});
test("gives up when the file cannot be read at all", async () => {
await withTempDir(async (folder) => {
// A folder where a file was expected: not "nothing here", but a disk we
// cannot make sense of.
await expect(readJsonOrNull(folder, NoteSchema)).rejects.toThrow();
});
});
});
describe("reading a JSON file the caller requires", () => {
test("gives back what the file holds", async () => {
await withTempDir(async (folder) => {
const path = join(folder, "note.json");
Deno.writeTextFileSync(path, '{ "note": "hello" }');
expect(await readJsonOrThrow(path, NoteSchema)).toEqual({
note: "hello",
});
});
});
test("fails loudly, naming the path, for a file that is not there", async () => {
await withTempDir(async (folder) => {
const path = join(folder, "missing.json");
await expect(readJsonOrThrow(path, NoteSchema)).rejects.toThrow(path);
});
});
test("fails loudly for text of the wrong shape", async () => {
await withTempDir(async (folder) => {
const path = join(folder, "note.json");
Deno.writeTextFileSync(path, '{ "other": 1 }');
await expect(readJsonOrThrow(path, NoteSchema)).rejects.toThrow();
});
});
});
describe("writing a JSON file a person reviews", () => {
test("writes indented, newline-terminated JSON that reads back the same", async () => {
await withTempDir(async (folder) => {
const path = join(folder, "counts.json");
await writeJsonFile(path, { "a.md": 1 });
const text = Deno.readTextFileSync(path);
expect(text).toBe('{\n "a.md": 1\n}\n');
expect(JSON.parse(text)).toEqual({ "a.md": 1 });
});
});
test("refuses a value that does not serialize, naming the path", async () => {
await withTempDir(async (folder) => {
const path = join(folder, "broken.json");
await expect(writeJsonFile(path, undefined)).rejects.toThrow(path);
// The refused write left nothing behind.
expect(() => Deno.readTextFileSync(path)).toThrow();
});
});
});
describe("a schema that accepts JSON null", () => {
test("refuses a file holding null, rather than reading it as missing", async () => {
await withTempDir(async (folder) => {
const path = join(folder, "null.json");
Deno.writeTextFileSync(path, "null");
const reads = readJsonOrNull(path, v.null());
await expect(reads).rejects.toThrow(path);
});
});
test("refuses the same read through readJsonOrThrow", async () => {
await withTempDir(async (folder) => {
const path = join(folder, "null.json");
Deno.writeTextFileSync(path, "null");
await expect(readJsonOrThrow(path, v.null())).rejects.toThrow("nothing");
});
});
test("answers nothing for half-written text, before the schema sees it", async () => {
await withTempDir(async (folder) => {
const path = join(folder, "null.json");
Deno.writeTextFileSync(path, '{ "note": "hel');
await expect(readJsonOrNull(path, v.null())).resolves.toBeNull();
});
});
});