import assert from 'node:assert/strict' import test from 'node:test' import { apply } from '../bundle/index.js' import { collectSelfCheck } from '../bundle/lib/selfcheck.js' import { registerCheckCommand } from '../bundle/command-check.js' const FEATURES = ['guards', 'bootstrap', 'commands', 'workingDirectory'] /** A ctx-like with every service the bundle depends on. */ function fullCtx() { return { tools: { guard() {} }, on() {}, inject() {}, workingDirectory: { get() {} }, } } test('collectSelfCheck ok on full ctx-like', () => { const report = collectSelfCheck(fullCtx()) assert.deepEqual( report.map((entry) => entry.feature), FEATURES, ) for (const entry of report) { assert.equal(entry.ok, true, `${entry.feature} ok`) assert.equal(typeof entry.detail, 'string', `${entry.feature} detail is a string`) assert.ok(entry.detail.length > 0, `${entry.feature} detail is non-empty`) } }) test('collectSelfCheck flags missing tools.guard', () => { const ctx = fullCtx() ctx.tools = {} const report = collectSelfCheck(ctx) const guards = report.find((entry) => entry.feature === 'guards') assert.equal(guards.ok, false) assert.match(guards.detail, /tools\.guard/) for (const entry of report.filter((entry) => entry.feature !== 'guards')) { assert.equal(entry.ok, true, `${entry.feature} stays ok`) } }) test('collectSelfCheck flags missing on()', () => { const ctx = fullCtx() ctx.on = undefined const report = collectSelfCheck(ctx) const bootstrap = report.find((entry) => entry.feature === 'bootstrap') assert.equal(bootstrap.ok, false) for (const entry of report.filter((entry) => entry.feature !== 'bootstrap')) { assert.equal(entry.ok, true, `${entry.feature} stays ok`) } }) test('collectSelfCheck skips features disabled by config', () => { const report = collectSelfCheck(fullCtx(), { guards: false, bootstrap: false, roleCommand: false, checkCommand: false, }) assert.deepEqual( report.map((entry) => entry.feature), ['workingDirectory'], ) }) test('collectSelfCheck does not flag a disabled feature that is also missing', () => { const ctx = fullCtx() ctx.tools = {} ctx.on = undefined const report = collectSelfCheck(ctx, { guards: false, bootstrap: false }) assert.deepEqual( report.map((entry) => entry.feature), ['commands', 'workingDirectory'], ) assert.ok(report.every((entry) => entry.ok), 'nothing not-ok in the report') const noInject = fullCtx() noInject.inject = undefined const commandsOff = collectSelfCheck(noInject, { roleCommand: false, checkCommand: false }) assert.ok(!commandsOff.some((entry) => entry.feature === 'commands'), 'commands skipped') assert.ok(commandsOff.every((entry) => entry.ok), 'missing inject not flagged') const roleOnly = collectSelfCheck(noInject, { roleCommand: false }) assert.ok(roleOnly.some((entry) => entry.feature === 'commands'), 'commands still checked') assert.equal( roleOnly.find((entry) => entry.feature === 'commands').ok, false, 'checkCommand alone still needs ctx.inject', ) }) test('registerCheckCommand builds report text', async () => { let captured const commands = { register(def) { captured = def }, } registerCheckCommand({ commands, collect: () => collectSelfCheck(fullCtx()) }) assert.equal(captured.name, 'dsh-harness-check') const okResult = await captured.handler({}) assert.match(okResult.text, /guards: ok/) assert.match(okResult.text, /all ok/) const brokenCtx = fullCtx() brokenCtx.tools = {} registerCheckCommand({ commands, collect: () => collectSelfCheck(brokenCtx) }) const badResult = await captured.handler({}) assert.match(badResult.text, /guards: not-ok/) assert.match(badResult.text, /problem/) }) /** Logger fake that interpolates `%s` and records error lines. */ function recordingLogger(errors) { return { info() {}, warn() {}, error(fmt, ...args) { const line = fmt.replace(/%s/g, () => String(args.shift() ?? '')) errors.push(line) }, } } test('apply does not throw when ctx.on and ctx.inject are missing', () => { const calls = { guard: 0 } const errors = [] const ctx = { tools: { guard() { calls.guard += 1 } }, workingDirectory: { get() {} }, logger: recordingLogger(errors), } assert.doesNotThrow(() => apply(ctx)) assert.equal(calls.guard, 1, 'guards feature stays wired') assert.ok( errors.some((line) => line.includes('self-check: bootstrap not-ok')), 'bootstrap not-ok is logged', ) assert.ok( errors.some((line) => line.includes('self-check: commands not-ok')), 'commands not-ok is logged', ) }) test('apply wires guards, bootstrap, and commands with a full ctx', () => { const calls = { guard: 0, on: 0, inject: 0 } const ctx = { tools: { guard() { calls.guard += 1 } }, on() { calls.on += 1 }, inject() { calls.inject += 1 }, workingDirectory: { get() {} }, logger: { info() {}, warn() {}, error() {} }, } assert.doesNotThrow(() => apply(ctx)) assert.equal(calls.guard, 1, 'guards wired') assert.equal(calls.on, 1, 'bootstrap wired') assert.equal(calls.inject, 1, 'commands wired') })