Maintainer CHANGES_REQUESTED (reviewede08667e5, pre-portability-fix): - B1: lint-rule no longer greens an unparseable target (eslintHasFatalError -> fail closed on any fatal/parse error) or an inline-suppressed violation (eslintJsonHasRule now scans suppressedMessages too). RED-first + real-runner repros. - B2: both child spawns get a bounded timeout (30s node / 60s eslint) + 16MiB maxBuffer; timeout fails closed. Injectable timeoutMs (positive-only — 0/negative can't disable the bound) enables a fast 1.5s hang test. - M1: scoped verify-phase.md — the check descriptor is author-supplied for now; filed #1278 for deterministic auto-locate of the descriptor (the locate half). - M2: added tests/prohibition-enforcement.property.test.cjs (fast-check fail-closed invariants; within the <=2-file budget). - m1: tapTestNames excludes # SKIP/# TODO; parseNodeTestSummary tracks # cancelled; isNonVacuousNodeTestPass requires cancelled===0. - m2: scoped the determinism claim to the decision/parse layer (real runner is env-dependent). - m3: filed #1279 for machine-proven fail-first (violation-fixture probe). - n1: -- before target in both arg builders (option-injection). n2: dropped dead token. - B3 (Windows npx) was already fixed in2af76306(pushed ~65s after the review). Verified node 22 + 24; size baseline regenerated for the verify-phase note.
61 lines
3.0 KiB
JavaScript
61 lines
3.0 KiB
JavaScript
// Property-based tests for the prohibition-enforcement parsing/transform helpers (#1259, ADR-550 D5d).
|
|
// RULESET.TESTS.property-based-testing: the producer is a parsing module (parseNodeTestSummary,
|
|
// tapTestNames, eslintJsonHasRule, eslintHasFatalError, eslintFileResultCount), so it carries
|
|
// fast-check invariants — especially the fail-closed safety invariants of the verify-time gate.
|
|
'use strict';
|
|
process.env.GSD_TEST_MODE = '1';
|
|
|
|
const { test, describe } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const path = require('node:path');
|
|
const fc = require('./helpers/fast-check-setup.cjs');
|
|
|
|
const ENFORCEMENT_LIB = path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'prohibition-enforcement.cjs');
|
|
|
|
describe('prohibition-enforcement properties (#1259)', () => {
|
|
test('parseNodeTestSummary never throws and returns non-negative integer counts', () => {
|
|
const enforce = require(ENFORCEMENT_LIB);
|
|
fc.assert(fc.property(fc.string(), (s) => {
|
|
const r = enforce.parseNodeTestSummary(s);
|
|
for (const k of ['tests', 'pass', 'fail', 'cancelled']) {
|
|
assert.ok(Number.isInteger(r[k]) && r[k] >= 0, `${k} is a non-negative integer`);
|
|
}
|
|
}));
|
|
});
|
|
|
|
test('isNonVacuousNodeTestPass FAIL-CLOSED: a run with any failure or cancellation never greens', () => {
|
|
const enforce = require(ENFORCEMENT_LIB);
|
|
fc.assert(fc.property(
|
|
fc.nat({ max: 50 }), fc.integer({ min: 1, max: 50 }), fc.nat({ max: 50 }), fc.string(),
|
|
(tests, failOrCancel, pass, name) => {
|
|
// A summary with fail>=1 (and, separately, cancelled>=1) must NEVER be a non-vacuous pass,
|
|
// regardless of the reported test name.
|
|
const failing = `ok 1 - ${name}\n# tests ${tests + 1}\n# pass ${pass}\n# fail ${failOrCancel}\n# cancelled 0\n`;
|
|
assert.equal(enforce.isNonVacuousNodeTestPass(failing, 'neg.test.cjs'), false);
|
|
const cancelled = `ok 1 - ${name}\n# tests ${tests + 1}\n# pass ${pass}\n# fail 0\n# cancelled ${failOrCancel}\n`;
|
|
assert.equal(enforce.isNonVacuousNodeTestPass(cancelled, 'neg.test.cjs'), false);
|
|
},
|
|
));
|
|
});
|
|
|
|
test('eslintJsonHasRule / eslintHasFatalError FAIL-CLOSED on any non-JSON / non-array input', () => {
|
|
const enforce = require(ENFORCEMENT_LIB);
|
|
fc.assert(fc.property(fc.string(), (s) => {
|
|
// Only exercise strings that are NOT a valid JSON array (the unreadable-report branch).
|
|
let isArray = false;
|
|
try { isArray = Array.isArray(JSON.parse(s)); } catch { isArray = false; }
|
|
fc.pre(!isArray);
|
|
assert.equal(enforce.eslintJsonHasRule(s, 'local/no-source-grep'), true, 'unreadable report -> violation (fail-closed)');
|
|
assert.equal(enforce.eslintHasFatalError(s), true, 'unreadable report -> fatal (fail-closed)');
|
|
}));
|
|
});
|
|
|
|
test('eslintFileResultCount never throws and is non-negative', () => {
|
|
const enforce = require(ENFORCEMENT_LIB);
|
|
fc.assert(fc.property(fc.string(), (s) => {
|
|
const n = enforce.eslintFileResultCount(s);
|
|
assert.ok(Number.isInteger(n) && n >= 0);
|
|
}));
|
|
});
|
|
});
|