Ctrl K
ComunidadGuías…

test/scripts/read-json.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
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();
    });
  });
});