Files
ECC/tests/lib/claude-settings-array.test.js
T

89 lines
3.3 KiB
JavaScript

'use strict';
const assert = require('assert');
const { spawnSync } = require('child_process');
const { materializeManagedHooks } = require('../../scripts/lib/install/claude-settings');
function config(command) {
return {
hooks: {
Stop: [{ id: 'ecc:array', hooks: [{ type: 'command', command }] }],
},
};
}
function materialize(command, root = '/opt/ecc') {
return materializeManagedHooks(config(command), root).Stop[0].hooks[0].command;
}
const tests = [
['materializes every array command without changing the source', () => {
const source = config([
'node -e "var e=process.env.CLAUDE_PLUGIN_ROOT;console.log(e)"',
'node -e "var e=process.env.CLAUDE_PLUGIN_ROOT;console.log(e)"',
'${CLAUDE_PLUGIN_ROOT}/scripts/start.js',
'--unchanged',
]);
const before = JSON.parse(JSON.stringify(source));
const command = materializeManagedHooks(source, '/opt/ecc').Stop[0].hooks[0].command;
assert.deepStrictEqual(source, before);
assert.notStrictEqual(command, source.hooks.Stop[0].hooks[0].command);
assert.ok(command.slice(0, 2).every(value => !value.includes('process.env.CLAUDE_PLUGIN_ROOT')));
assert.deepStrictEqual(command.slice(2), ['/opt/ecc/scripts/start.js', '--unchanged']);
}],
['array argv commands execute with the exact root in a clean process', () => {
const root = '/tmp/ECC space/\'"$`\\路径';
const command = materialize([
process.execPath,
'-e',
'var e=process.env.CLAUDE_PLUGIN_ROOT;process.stdout.write(e);',
], root);
const result = spawnSync(command[0], command.slice(1), {
env: {},
encoding: 'utf8',
timeout: 5000,
});
assert.ifError(result.error);
assert.strictEqual(result.status, 0, result.stderr);
assert.strictEqual(result.stdout, root);
}],
...[0, 1].map(index => [
`rejects an unresolved root read in array element ${index}`,
() => {
const command = ['echo first', 'echo second'];
command[index] = 'node -e "const root=process.env.CLAUDE_PLUGIN_ROOT"';
assert.throws(() => materialize(command), /Unable to resolve CLAUDE_PLUGIN_ROOT/);
},
]),
['rejects a remaining root read after resolving an array prologue', () => {
assert.throws(() => materialize([
'var e=process.env.CLAUDE_PLUGIN_ROOT;console.log(process.env.CLAUDE_PLUGIN_ROOT);',
]), /Unable to resolve CLAUDE_PLUGIN_ROOT/);
}],
['retains supported root assignments in array commands', () => {
const command = materialize([
'var e=process.env.CLAUDE_PLUGIN_ROOT;process.env.CLAUDE_PLUGIN_ROOT=e;',
]);
assert.ok(!command[0].includes('var e=process.env.CLAUDE_PLUGIN_ROOT;'));
assert.ok(command[0].includes('process.env.CLAUDE_PLUGIN_ROOT=e;'));
}],
['invalid arrays still fail command validation', () => {
for (const command of [[], ['node', null], ['node', 3], ['node', ' ']]) {
assert.throws(() => materialize(command), /invalid command/);
}
}],
];
let failed = 0;
for (const [name, run] of tests) {
try {
run();
console.log(` PASS ${name}`);
} catch (error) {
failed += 1;
console.error(` FAIL ${name}\n ${error.stack || error.message}`);
}
}
console.log(`\nResults: Passed: ${tests.length - failed}, Failed: ${failed}`);
process.exitCode = failed > 0 ? 1 : 0;