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
|
// modules/test/test-pipe-guard.js — run: node modules/test/test-pipe-guard.js
// Fails fast if either guard is removed or if a guard is placed AFTER the parts[0] read.
// Behavioural proof is the browser matrix (plan Task 8); this test is the cheap tripwire.
const fs = require('fs'), path = require('path');
const src = fs.readFileSync(path.join(__dirname, '../core/terminal.js'), 'utf8');
// 1. _parseArgs('') must return [] — that precondition is what made parts[0] undefined.
// The source is a CLASS METHOD, so wrap it in an object literal (a bare `new Function('m(){…}')`
// is a SyntaxError). It touches no `this` (verified), so a detached call is safe.
const m = src.match(/_parseArgs\((\w+)\)\s*\{[\s\S]*?\n\s{12}\}/);
if (!m) { console.error('FAIL: _parseArgs not found — did the method signature or indent change?'); process.exit(1); }
const parseArgs = new Function('return ({' + m[0] + '})._parseArgs;')();
const empty = parseArgs('');
const blank = parseArgs(' ');
// 2. guards must exist AND precede the read they protect (ordering, not just presence)
const ci = src.indexOf('_classify(raw)');
const cGuard = src.indexOf('if (!parts.length)', ci);
const cRead = src.indexOf('parts[0].toLowerCase()', ci);
const classifyGuarded = ci >= 0 && cGuard > ci && cGuard < cRead;
const pi = src.indexOf('async executePipeChain(');
const pGuard = src.indexOf('if (!stages.length)', pi);
const pFilter = src.indexOf('.filter(argv => argv.length > 0)', pi);
const pRead = src.indexOf('argv[0].toLowerCase()', pi);
const pipeGuarded = pi >= 0 && pFilter > pi && pGuard > pFilter && pRead > pGuard
&& src.indexOf('i < stages.length - 1', pi) > 0;
const report = { empty, blank, classifyGuarded, pipeGuarded };
console.log(JSON.stringify(report));
const ok = Array.isArray(empty) && empty.length === 0
&& Array.isArray(blank) && blank.length === 0
&& classifyGuarded && pipeGuarded;
process.exit(ok ? 0 : 1);
|