aboutsummaryrefslogtreecommitdiff
path: root/modules/test/test-loop-policy.js
diff options
context:
space:
mode:
Diffstat (limited to 'modules/test/test-loop-policy.js')
-rw-r--r--modules/test/test-loop-policy.js74
1 files changed, 74 insertions, 0 deletions
diff --git a/modules/test/test-loop-policy.js b/modules/test/test-loop-policy.js
new file mode 100644
index 0000000..340e308
--- /dev/null
+++ b/modules/test/test-loop-policy.js
@@ -0,0 +1,74 @@
+// modules/test/test-loop-policy.js — run: node
+// MAINT-004: the loop guard must read the config it documents — `threshold` as an alias, and
+// `enabled: false` must actually switch it off (it was never read at all).
+const fsMod = require('fs'), path = require('path');
+const ROOT = path.join(__dirname, '..', 'core');
+const store = {};
+global.localStorage = { getItem: k => (k in store ? store[k] : null), setItem: (k, v) => { store[k] = String(v); }, removeItem: k => { delete store[k]; } };
+global.indexedDB = { open() { throw new Error('no idb'); }, deleteDatabase() { throw new Error('no idb'); } };
+global.window = global;
+
+const AI = new Function(fsMod.readFileSync(path.join(ROOT, 'module-aiassist.js'), 'utf8') + '\nreturn WebX11AIAssistantModule;')();
+const ai = Object.create(AI.prototype);
+ai.terminal = { print: () => {}, log: () => {} };
+
+let fails = 0, passes = 0;
+function ok(name, cond, detail) {
+ if (cond) { passes++; return; }
+ fails++;
+ console.log('FAIL ' + name + (detail ? ' — ' + detail : ''));
+}
+
+// A. defaults
+{
+ const p = ai._loopPolicy(undefined);
+ ok('A1 enabled by default', p.enabled === true);
+ ok('A2 default warn/block/hardstop', p.warnAt === 3 && p.blockAt === 6 && p.hardStopAt === 9, JSON.stringify(p));
+ ok('A3 default window', p.windowMs === 30000);
+}
+
+// B. `threshold` is honoured (the old code ignored it entirely)
+{
+ const p = ai._loopPolicy({ threshold: 4 });
+ ok('B1 threshold sets blockAt', p.blockAt === 4, JSON.stringify(p));
+ ok('B2 warn comes before block', p.warnAt < p.blockAt, JSON.stringify(p));
+ ok('B3 hard stop comes after block', p.hardStopAt > p.blockAt, JSON.stringify(p));
+}
+
+// C. explicit values win over the alias
+{
+ const p = ai._loopPolicy({ threshold: 4, blockAt: 8, warnAt: 5, hardStopAt: 12 });
+ ok('C1 blockAt wins over threshold', p.blockAt === 8, JSON.stringify(p));
+ ok('C2 warnAt respected', p.warnAt === 5, JSON.stringify(p));
+ ok('C3 hardStopAt respected', p.hardStopAt === 12, JSON.stringify(p));
+}
+
+// D. `enabled: false` is a real kill switch
+{
+ const p = ai._loopPolicy({ enabled: false, threshold: 3 });
+ ok('D1 disable is reported', p.enabled === false, JSON.stringify(p));
+ ok('D2 disable keeps the numbers for display', p.blockAt === 3, JSON.stringify(p));
+}
+
+// E. nonsense input cannot produce a backwards policy
+{
+ const p = ai._loopPolicy({ warnAt: 9, blockAt: 6, hardStopAt: 2 });
+ ok('E1 warn never exceeds block', p.warnAt <= p.blockAt, JSON.stringify(p));
+ ok('E2 hard stop never equals block', p.hardStopAt > p.blockAt, JSON.stringify(p));
+}
+
+// F. the guard actually consults the policy in the loop source
+{
+ const src = fsMod.readFileSync(path.join(ROOT, 'module-aiassist.js'), 'utf8');
+ ok('F1 the loop uses the resolver', /var _lp = this\._loopPolicy\(loopDetect\)/.test(src));
+ ok('F2 blocking is gated on enabled', /_lp\.enabled && \(entry\.blocked \|\| entry\.count >= _blockAt\)/.test(src));
+ ok('F3 warning is gated on enabled', /_lp\.enabled && entry\.count === _warnAt/.test(src));
+ ok('F4 no direct reads of loopDetect.warnAt/blockAt remain', !/loopDetect\.(warnAt|blockAt|hardStopAt)/.test(src));
+}
+
+if (fails === 0) {
+ console.log('test-loop-policy: ' + passes + ' passed, 0 failed');
+} else {
+ console.log('test-loop-policy: ' + passes + ' passed, ' + fails + ' FAILED');
+ process.exit(1);
+}