198 lines
6.1 KiB
TypeScript
198 lines
6.1 KiB
TypeScript
// tests/unit/build/check-pr-evidence.test.ts
|
|
// TDD tests for the evaluatePrBody() pure function in check-pr-evidence.mjs.
|
|
// Validates that the gate correctly detects outcome claims and evidence blocks.
|
|
import test from "node:test";
|
|
import assert from "node:assert/strict";
|
|
import { evaluatePrBody } from "../../../scripts/check/check-pr-evidence.mjs";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// (a) Body with claim + evidence block => PASS
|
|
// ---------------------------------------------------------------------------
|
|
|
|
test("evaluatePrBody: strong claim + fenced code block with test output => pass", () => {
|
|
const body = `
|
|
## Summary
|
|
Fixed the null-pointer bug.
|
|
|
|
All tests pass.
|
|
|
|
## Output
|
|
\`\`\`
|
|
42 passing (3s)
|
|
0 failing
|
|
\`\`\`
|
|
`;
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "pass");
|
|
});
|
|
|
|
test("evaluatePrBody: strong claim + inline result code span => pass", () => {
|
|
const body = "Typecheck is clean. Result: `42 passing`";
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "pass");
|
|
});
|
|
|
|
test("evaluatePrBody: strong claim + Evidence section header with content => pass", () => {
|
|
const body = `
|
|
Fixed the regression.
|
|
Validated locally.
|
|
|
|
## Evidence
|
|
node --import tsx/esm --test tests/unit/foo.test.ts
|
|
14 tests passed, 0 failed.
|
|
`;
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "pass");
|
|
});
|
|
|
|
test("evaluatePrBody: 'all green' claim + fenced block with PASS token => pass", () => {
|
|
const body = `
|
|
All tests are green.
|
|
|
|
\`\`\`
|
|
PASS src/foo.test.ts
|
|
Test Suites: 1 passed, 1 total
|
|
Tests: 5 passed, 5 total
|
|
\`\`\`
|
|
`;
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "pass");
|
|
});
|
|
|
|
test("evaluatePrBody: two weak triggers + fenced code block with output => pass", () => {
|
|
const body = `
|
|
Added a new endpoint for health checks.
|
|
Resolves #123.
|
|
|
|
\`\`\`
|
|
npm run test
|
|
14 passing (1s)
|
|
\`\`\`
|
|
`;
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "pass");
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// (b) Body with claim + NO evidence block => FAIL
|
|
// ---------------------------------------------------------------------------
|
|
|
|
test("evaluatePrBody: 'all tests pass' with no evidence => fail", () => {
|
|
const body = "Fixed the bug. All tests pass and I added a new endpoint.";
|
|
const { result, reason } = evaluatePrBody(body);
|
|
assert.equal(result, "fail");
|
|
assert.ok(reason.includes("Rule #18"), `reason should mention Rule #18, got: ${reason}`);
|
|
});
|
|
|
|
test("evaluatePrBody: 'typecheck is clean' with no evidence => fail", () => {
|
|
const body = "Refactored the module. Typecheck pass and lint is clean.";
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "fail");
|
|
});
|
|
|
|
test("evaluatePrBody: 'tests passing' + fenced block with no output-like content => fail", () => {
|
|
const body = `
|
|
Tests are passing!
|
|
|
|
\`\`\`ts
|
|
// just a code snippet, not output
|
|
export function foo() { return 42; }
|
|
\`\`\`
|
|
`;
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "fail");
|
|
});
|
|
|
|
test("evaluatePrBody: two weak triggers + no evidence => fail", () => {
|
|
const body = "Fixed the issue. Resolves #456. Looks good to me.";
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "fail");
|
|
});
|
|
|
|
test("evaluatePrBody: 'validated on VPS' with no evidence block => fail", () => {
|
|
const body = "Validated on VPS. Everything works correctly.";
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "fail");
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// (c) Body with no claim terms => PASS
|
|
// ---------------------------------------------------------------------------
|
|
|
|
test("evaluatePrBody: body without any claim terms => pass", () => {
|
|
const body = `
|
|
## Summary
|
|
Update the README with new provider list.
|
|
Adds documentation for the new streaming format.
|
|
`;
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "pass");
|
|
});
|
|
|
|
test("evaluatePrBody: body with only one weak trigger => pass (not enough to fire)", () => {
|
|
const body = "Resolves #789 by updating the config file.";
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "pass");
|
|
});
|
|
|
|
test("evaluatePrBody: body describing a pure docs change with no claims => pass", () => {
|
|
const body = "Updates ARCHITECTURE.md to reflect the new combo routing design.";
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "pass");
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// (d) Empty/missing body => SKIP (or pass — no blocking)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
test("evaluatePrBody: empty string => skip", () => {
|
|
const { result } = evaluatePrBody("");
|
|
assert.equal(result, "skip");
|
|
});
|
|
|
|
test("evaluatePrBody: whitespace-only string => skip", () => {
|
|
const { result } = evaluatePrBody(" \n \t ");
|
|
assert.equal(result, "skip");
|
|
});
|
|
|
|
test("evaluatePrBody: undefined body => skip (treat as empty)", () => {
|
|
// @ts-expect-error — testing defensive path
|
|
const { result } = evaluatePrBody(undefined);
|
|
assert.equal(result, "skip");
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Edge cases
|
|
// ---------------------------------------------------------------------------
|
|
|
|
test("evaluatePrBody: fenced block with exit-code output => pass (strong trigger present)", () => {
|
|
const body = `
|
|
Fixes the build. Zero errors after this change.
|
|
|
|
\`\`\`
|
|
$ npm run typecheck
|
|
exit code 0
|
|
\`\`\`
|
|
`;
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "pass");
|
|
});
|
|
|
|
test("evaluatePrBody: evidence section header present but with minimal content => pass (strong trigger)", () => {
|
|
// "Validated locally" is a strong trigger. Evidence section has 25+ chars.
|
|
const body = `
|
|
Validated locally on the production VPS.
|
|
|
|
## Validation
|
|
Ran the full test suite and observed 0 failures from the terminal.
|
|
`;
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "pass");
|
|
});
|
|
|
|
test("evaluatePrBody: inline PASSED span counts as evidence", () => {
|
|
const body = "All tests pass. Result: `PASSED 14 tests`";
|
|
const { result } = evaluatePrBody(body);
|
|
assert.equal(result, "pass");
|
|
});
|