test(h3d-carve-6): strengthen stale-private guard to catch full class (Toby r1)

Replace hardcoded ['_pmXSpriteMat','_fhXSpriteMat'] list in test 4 with
a full factory-depth-1 scan of materials.js (4-space indent const/let
declarations NOT in the return set). This catches TXT_STYLES and any
future factory-private additions automatically.

Mutation-verified: void TXT_STYLES injected into screen.js → test 4 RED;
reverted → 16/16 GREEN. Full h3d suite: 253/253, 0 fail.
Command: node --test tests/js/highway_3d*.test.js plugins/highway_3d/tests/*.test.js

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014uZ169yfoFYArXz962g7KW
This commit is contained in:
byrongamatos
2026-09-05 12:40:34 +02:00
co-authored by Claude Sonnet 4.6
parent e6b2f86068
commit a993d2b291
+35 -12
View File
@@ -140,19 +140,42 @@ test('every symbol returned by createMaterialBuilders is in the screen.js destru
'createMaterialBuilders returns symbols not in screen.js destructure: ' + leaked.join(', ')); 'createMaterialBuilders returns symbols not in screen.js destructure: ' + leaked.join(', '));
}); });
// ── 4. Stale-private guard: _pm/_fhXSpriteMat not bare in screen.js ────────── // ── 4. Stale-private guard: factory-private symbols not bare in screen.js ──────
test('_pmXSpriteMat and _fhXSpriteMat do not appear bare in screen.js IIFE body', () => { test('factory-private symbols in materials.js do not appear bare in screen.js', () => {
// Mutation: reference _pmXSpriteMat directly in screen.js body → RED. // Mutation: add bare TXT_STYLES to screen.js body → violations=['TXT_STYLES'] → RED.
// These two let vars were factory-scope in the old N-section; now they live // Kills the whole class: any factory-depth-1 const/let NOT in the return set
// in the materials.js module closure and must not appear in screen.js. // must not leak into screen.js. Catches TXT_STYLES, _pmXSpriteMat, _fhXSpriteMat
const scr = screenSrc(); // and any future factory-private additions automatically.
let scrStripped = scr.replace(/^import\s+.*\n/gm, ''); const matSrc = stripComments(src());
scrStripped = stripComments(scrStripped); const scrRaw = screenSrc();
scrStripped = scrStripped.replace(/const\s*\{[^}]+\}\s*=\s*createMaterialBuilders\s*\([^)]*\)\s*;/, '');
for (const sym of ['_pmXSpriteMat', '_fhXSpriteMat']) { // Extract the returned symbol set (reuse test 3's anchor).
assert.doesNotMatch(scrStripped, new RegExp('\\b' + sym + '\\b'), const retMatch = matSrc.match(/return\s*\{\s*\n\s*(txtMat\s*,[\s\S]+?)\n\s*\};/);
`screen.js must not reference private module var ${sym}`); assert.ok(retMatch, 'return block must be present');
const returned = new Set(
retMatch[1].split(',').map(s => s.trim()).filter(Boolean)
);
// Factory-depth-1 const/let declarations: exactly 4-space indent.
// These are factory-private vars (_pmXSpriteMat, _fhXSpriteMat, TXT_STYLES …).
// Depth-2 locals (const T = getT() etc.) have 8+ spaces — excluded by anchor.
const privateSyms = [];
for (const m of matSrc.matchAll(/^ {4}(?:const|let)\s+(\w+)/gm)) {
const sym = m[1];
if (!returned.has(sym)) privateSyms.push(sym);
} }
assert.ok(privateSyms.length > 0, 'factory must have at least one private depth-1 declaration');
// Strip screen.js of import lines, comments, and the destructure line.
let scr = scrRaw.replace(/^import\s+.*\n/gm, '');
scr = stripComments(scr);
scr = scr.replace(/const\s*\{[^}]+\}\s*=\s*createMaterialBuilders\s*\([^)]*\)\s*;/, '');
const violations = privateSyms.filter(sym =>
new RegExp('\\b' + sym + '\\b').test(scr)
);
assert.deepStrictEqual(violations, [],
'screen.js must not reference factory-private materials.js symbols: ' + violations.join(', '));
}); });
// ── 5. DI: T is accessed via getT() at call time, not factory construction ─── // ── 5. DI: T is accessed via getT() at call time, not factory construction ───