Ctrl K
ComunidadGuías…

test/scripts/coverage-exclusions-ratchet.test.ts

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

Archivo original ↗Preguntar a KiBot
import { assertStringIncludes } from "@std/assert";
import { expect } from "@std/expect";
import { describe, it as test } from "@std/testing/bdd";
import {
  EXCLUSIONS_PATH,
  LEGACY_PATH,
  RATCHET_GUIDE,
} from "#scripts/check-coverage-exclusions/exclusion-ratchet.ts";
import {
  baseEntries,
  ratchetExit,
} from "#scripts/check-coverage-exclusions/ratchet-run.ts";
import { gitShow, holds, lsTree, stubRun } from "#test-utils/git-stub.ts";

const module = (entries: string[]): string =>
  `${entries.map((entry) => `  "${entry}",`).join("\n")}\n`;

describe("baseEntries", () => {
  test("reads the data module at the merge base", async () => {
    const run = stubRun({
      [lsTree("base123", EXCLUSIONS_PATH)]: holds(EXCLUSIONS_PATH),
      [gitShow("base123", EXCLUSIONS_PATH)]: {
        code: 0,
        stdout: module(["src/a.ts"]),
      },
    });
    expect(await baseEntries(run, "base123")).toEqual(["src/a.ts"]);
  });

  test("falls back to the gate module the list moved out of", async () => {
    const run = stubRun({
      [lsTree("base123", EXCLUSIONS_PATH)]: {
        code: 0,
        stdout: "",
      },
      [lsTree("base123", LEGACY_PATH)]: holds(LEGACY_PATH),
      [gitShow("base123", LEGACY_PATH)]: {
        code: 0,
        stdout: module(["src/old.ts"]),
      },
    });
    expect(await baseEntries(run, "base123")).toEqual(["src/old.ts"]);
  });

  test("answers an empty base when neither file exists there", async () => {
    const run = stubRun({
      [lsTree("base123", EXCLUSIONS_PATH)]: { code: 0, stdout: "" },
      [lsTree("base123", LEGACY_PATH)]: { code: 0, stdout: "" },
    });
    expect(await baseEntries(run, "base123")).toEqual([]);
  });

  test("surfaces a probe failure that is not a missing path", async () => {
    const run = stubRun({
      [lsTree("base123", EXCLUSIONS_PATH)]: {
        code: 128,
        stderr: "fatal: bad object base123",
        stdout: "",
      },
    });
    await expect(baseEntries(run, "base123")).rejects.toThrow(/bad object/);
  });

  test("surfaces a read failure after the path checks out", async () => {
    const run = stubRun({
      [lsTree("base123", EXCLUSIONS_PATH)]: holds(EXCLUSIONS_PATH),
      [gitShow("base123", EXCLUSIONS_PATH)]: {
        code: 128,
        stderr: "fatal: bad object base123",
        stdout: "",
      },
    });
    await expect(baseEntries(run, "base123")).rejects.toThrow(/bad object/);
  });
});

describe("ratchetExit", () => {
  const lines: string[] = [];
  const output = {
    log: (line: string) => lines.push(line),
    logError: (line: string) => lines.push(line),
  };

  /** Run the ratchet over `head` against a base that holds `base`, with
   * `runtime` as the array the gate imports and the report lines collected
   * for the assertions. */
  const exitFor = async (
    head: string[],
    base: string[],
    runtime: readonly string[] = head,
  ): Promise<number> => {
    lines.length = 0;
    const run = stubRun({
      "git merge-base HEAD origin/main": { code: 0, stdout: "base123" },
      [lsTree("base123", EXCLUSIONS_PATH)]: holds(EXCLUSIONS_PATH),
      [gitShow("base123", EXCLUSIONS_PATH)]: {
        code: 0,
        stdout: module(base),
      },
    });
    return ratchetExit(run, module(head), runtime, output);
  };

  test("exits 0 and reports nothing added on a clean list", async () => {
    expect(await exitFor(["src/a.ts"], ["src/a.ts"])).toBe(0);
    expect(lines).toEqual([
      "The coverage exclusion list adds nothing against origin/main.",
    ]);
  });

  test("exits 1 and names each added entry", async () => {
    expect(await exitFor(["src/a.ts", "src/new.ts"], ["src/a.ts"])).toBe(1);
    assertStringIncludes(lines.join("\n"), "src/new.ts");
    assertStringIncludes(lines.join("\n"), RATCHET_GUIDE);
  });

  test("fails loudly when an entry hides from the parser", async () => {
    const head = [
      "export const COVERAGE_EXCLUSIONS = [",
      '  "src/a.ts",',
      '  "src/b.ts", /* hidden from the line parser */',
      "];",
      "",
    ].join("\n");
    lines.length = 0;
    const run = stubRun({
      "git merge-base HEAD origin/main": { code: 0, stdout: "base123" },
      [gitShow("base123", EXCLUSIONS_PATH)]: {
        code: 0,
        stdout: module(["src/a.ts"]),
      },
    });
    await expect(
      ratchetExit(run, head, ["src/a.ts", "src/b.ts"], output),
    ).rejects.toThrow(/could not read 1 exclusion entries.*src\/b\.ts/s);
  });

  test("fails loudly when origin/main is missing", async () => {
    lines.length = 0;
    const run = stubRun({
      "git merge-base HEAD origin/main": {
        code: 128,
        stderr: "fatal: not a valid revision",
        stdout: "",
      },
    });
    await expect(ratchetExit(run, module([]), [], output)).rejects.toThrow(
      /git fetch origin main/,
    );
  });
});