Files
msd-core/tests/enumeration-drift-guard.test.cjs
Jakub Zych a9a7a328e6 refactor: hard-fork GSD -> MSD (Make Software Done)
Mechanical rename produced by scripts/msd-rename.cjs: gsd/Gsd/GSD -> msd/Msd/MSD
across contents and paths, upstream package/repo coordinates -> @golem15/msd-core
and golem15com/msd-core. Deep links into upstream history, sibling upstream
packages, the GSD-2 import feature, CHANGELOG.md and .changeset/ are kept as-is.

Hand edits on top: MSD block-letter banner and logos, LICENSE copyright line,
package/plugin identity, regenerated lockfile, install-tree fixtures, derived
registries and benchmark baseline; migration checksum baseline re-locked
(MSD keeps its own install state, so no install had applied the old sums);
sort-order and regex-escaped expectations in tests adjusted.
2026-10-06 01:47:40 +02:00

139 lines
4.6 KiB
JavaScript

'use strict';
process.env.MSD_TEST_MODE = '1';
/**
* Unit coverage for the phase-ENUMERATION drift guard
* (scripts/lint-phase-enumeration-drift.cjs, epic #3180, issue #3185,
* ADR-3180 Decision 1 row "Phase enumeration").
*
* Modelled on tests/phase-id-drift-guard.test.cjs: this guard was previously
* exercised only via `lint:ci`, with no unit test of its own pure functions.
* Behavioral throughout: assertions drive `findPhaseEnumerationDrift` /
* `scanRepo` / `stripComments` directly — no `readFileSync().includes()` in
* a test body.
*/
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const path = require('node:path');
const ROOT = path.join(__dirname, '..');
const {
findPhaseEnumerationDrift,
scanRepo,
stripComments,
} = require(path.join(ROOT, 'scripts', 'lint-phase-enumeration-drift.cjs'));
describe('#3185 phase-enumeration drift scanner: findPhaseEnumerationDrift (pure)', () => {
test('a clean line carrying neither detector shape is not flagged', () => {
assert.deepEqual(
findPhaseEnumerationDrift("const { value: dirs } = listMilestonePhaseDirs(phasesDir, { cwd });", 'src/fake.cts'),
[],
);
});
test('an injected fs.readdirSync(phasesDir, ...) line IS flagged', () => {
const v = findPhaseEnumerationDrift(
"const names = fs.readdirSync(phasesDir, { withFileTypes: true });",
'src/fake.cts',
);
assert.equal(v.length, 1);
assert.equal(v[0].line, 1);
});
test('an injected /^999(?:\\.|$)/ sentinel literal IS flagged', () => {
const v = findPhaseEnumerationDrift(
"const isBacklog = /^999(?:\\.|$)/.test(dirName);",
'src/fake.cts',
);
assert.equal(v.length, 1);
assert.equal(v[0].line, 1);
});
test('a COMMENT containing either shape is NOT flagged', () => {
const readdirInComment = findPhaseEnumerationDrift(
"// legacy code used to do fs.readdirSync(phasesDir, { withFileTypes: true })",
'src/fake.cts',
);
assert.deepEqual(readdirInComment, []);
const sentinelInComment = findPhaseEnumerationDrift(
"// the old regex was /^999(?:\\.|$)/ before the single owner existed",
'src/fake.cts',
);
assert.deepEqual(sentinelInComment, []);
const blockCommentContinuation = findPhaseEnumerationDrift(
" * mirrors fs.readdirSync(phasesDir, { withFileTypes: true }) from before",
'src/fake.cts',
);
assert.deepEqual(blockCommentContinuation, []);
});
test('an unrelated numeric such as const n = total + 1999 is NOT flagged', () => {
assert.deepEqual(
findPhaseEnumerationDrift('const n = total + 1999;', 'src/fake.cts'),
[],
);
});
test('#2761 narrow 999-only rules are exempt only inside their named owners', () => {
const roadmapSource = [
'function scanMilestonePhaseIdSets() {',
' return /^999\\b/.test(token);',
'}',
'function unrelatedRoadmapReader() {',
' return /^999\\b/.test(token);',
'}',
].join('\n');
assert.deepEqual(
findPhaseEnumerationDrift(roadmapSource, path.join('src', 'roadmap-parser.cts')),
[{ line: 5, found: '/^999\\b/' }],
);
const stateSource = [
'function countRoadmapPhaseHeadings() {',
' return /^999\\b/.test(token);',
'}',
'function unrelatedStateReader() {',
' return /^999\\b/.test(token);',
'}',
].join('\n');
assert.deepEqual(
findPhaseEnumerationDrift(stateSource, path.join('src', 'state.cts')),
[{ line: 5, found: '/^999\\b/' }],
);
});
});
describe('#3185 phase-enumeration drift scanner: stripComments (pure)', () => {
test('a whole-line // comment strips to empty', () => {
assert.equal(stripComments('// just a comment'), '');
});
test('a JSDoc continuation line strips to empty', () => {
assert.equal(stripComments(' * some doc text'), '');
});
test('a trailing // comment after code strips only the comment portion', () => {
assert.equal(stripComments('const x = 1; // trailing note'), 'const x = 1; ');
});
test('a line with no comment is returned unchanged', () => {
const line = 'const dirs = listMilestonePhaseDirs(phasesDir, { cwd });';
assert.equal(stripComments(line), line);
});
});
describe('#3185 phase-enumeration drift scanner: the live repo is clean', () => {
test('scanRepo(repoRoot) returns zero unsanctioned re-derivations', () => {
const violations = scanRepo(ROOT);
assert.deepEqual(
violations,
[],
'unsanctioned phase-enumeration re-derivation(s) — route through listMilestonePhaseDirs / isSentinelPhaseId:\n' +
violations.map((d) => ` ${d.file}:${d.line} ${d.found}`).join('\n'),
);
});
});