Spaces:
Running
Running
File size: 3,687 Bytes
a9fbc84 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | import { execFileSync } from "node:child_process";
import fs from "node:fs";
import { createRequire } from "node:module";
import os from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const SCRIPT_PATH = path.resolve(__dirname, "documentation-validator.cjs");
const REPO_ROOT = path.resolve(__dirname, "..");
const { documentationFiles } = createRequire(import.meta.url)(SCRIPT_PATH);
function runValidator(rootDir, cwd = REPO_ROOT) {
try {
const output = execFileSync(process.execPath, [SCRIPT_PATH, rootDir], {
cwd,
encoding: "utf8",
stdio: "pipe",
});
return { exitCode: 0, stdout: output, stderr: "" };
} catch (error) {
if (error.signal) throw new Error(`Killed by ${error.signal}`);
return {
exitCode: error.status ?? 1,
stdout: error.stdout ?? "",
stderr: error.stderr ?? "",
};
}
}
function writeDoc(dir, relPath, content) {
const fullPath = path.join(dir, relPath);
fs.mkdirSync(path.dirname(fullPath), { recursive: true });
fs.writeFileSync(fullPath, content);
}
describe("documentation-validator", () => {
let tmpDir;
beforeEach(() => {
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "doc-validator-test-"));
for (const docFile of documentationFiles) {
writeDoc(tmpDir, docFile, "# Doc\n");
}
});
afterEach(() => {
fs.rmSync(tmpDir, { recursive: true, force: true });
});
it("lists no file this repository is missing", () => {
expect(runValidator(REPO_ROOT).stdout).not.toContain("File not found");
});
it("fails and counts the issue when a listed file is missing", () => {
const missing = ".github/ISSUE_TEMPLATE/bug_report.yml";
fs.rmSync(path.join(tmpDir, missing));
const { exitCode, stdout } = runValidator(tmpDir);
expect(exitCode).toBe(1);
expect(stdout).toContain(`File not found: ${missing}`);
expect(stdout).toMatch(/Issues found: 1$/m);
});
it("fails and counts the issue when a listed file cannot be read", () => {
const unreadable = path.join(tmpDir, ".github/SECURITY.md");
fs.rmSync(unreadable);
fs.mkdirSync(unreadable);
const { exitCode, stdout } = runValidator(tmpDir);
expect(exitCode).toBe(1);
expect(stdout).toContain("Error reading .github/SECURITY.md");
expect(stdout).toMatch(/Issues found: 1$/m);
});
it("counts a broken link the same way it reports it", () => {
writeDoc(tmpDir, "README.md", "# Doc\n\n[Gone](./nonexistent.md)\n");
const { exitCode, stdout } = runValidator(tmpDir);
expect(exitCode).toBe(1);
expect(stdout).toContain('Missing target: "./nonexistent.md"');
expect(stdout).toMatch(/Issues found: 1$/m);
});
it("rejects a root directory that does not exist", () => {
const { exitCode, stderr } = runValidator(path.join(tmpDir, "missing"));
expect(exitCode).toBe(1);
expect(stderr).toContain("Directory not found");
});
it("rejects a file given where a root directory belongs", () => {
const { exitCode, stderr } = runValidator(path.join(tmpDir, "README.md"));
expect(exitCode).toBe(1);
expect(stderr).toContain("Directory not found");
});
it("falls back to the repository root when the argument is empty", () => {
const elsewhere = fs.mkdtempSync(
path.join(os.tmpdir(), "doc-validator-cwd-"),
);
try {
expect(runValidator("", elsewhere).stdout).not.toContain(
"File not found",
);
} finally {
fs.rmSync(elsewhere, { recursive: true, force: true });
}
});
});
|