ci/woodpecker/push/publish Pipeline was canceled
Co-authored-by: orch-01 <[email protected]>
92 lines
3.5 KiB
TypeScript
92 lines
3.5 KiB
TypeScript
import { mkdirSync, mkdtempSync, writeFileSync, chmodSync } from 'node:fs';
|
|
import { tmpdir } from 'node:os';
|
|
import { join } from 'node:path';
|
|
|
|
import { Command } from 'commander';
|
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
|
|
import { registerQCommand, resolveQuestionTool } from './q.js';
|
|
import { exitStatusFor, resolveBrainTool } from './brain-dispatch.js';
|
|
|
|
describe('resolveBrainTool', () => {
|
|
const saved = process.env['MOSAIC_BRAIN_HOME'];
|
|
afterEach(() => {
|
|
if (saved === undefined) delete process.env['MOSAIC_BRAIN_HOME'];
|
|
else process.env['MOSAIC_BRAIN_HOME'] = saved;
|
|
});
|
|
|
|
it('joins brain home with the relative tool path', () => {
|
|
const tmp = mkdtempSync(join(tmpdir(), 'dispatch-resolve-'));
|
|
process.env['MOSAIC_BRAIN_HOME'] = tmp;
|
|
expect(resolveBrainTool('/nonexistent/mosaic-home', 'tools/questions/q-new.sh')).toBe(
|
|
join(tmp, 'tools', 'questions', 'q-new.sh'),
|
|
);
|
|
});
|
|
});
|
|
|
|
describe('resolveQuestionTool', () => {
|
|
const saved = process.env['MOSAIC_BRAIN_HOME'];
|
|
afterEach(() => {
|
|
if (saved === undefined) delete process.env['MOSAIC_BRAIN_HOME'];
|
|
else process.env['MOSAIC_BRAIN_HOME'] = saved;
|
|
});
|
|
|
|
it('maps new/render subcommands to their brain tools', () => {
|
|
const tmp = mkdtempSync(join(tmpdir(), 'q-resolve-'));
|
|
process.env['MOSAIC_BRAIN_HOME'] = tmp;
|
|
expect(resolveQuestionTool(tmp, 'new')).toBe(join(tmp, 'tools', 'questions', 'q-new.sh'));
|
|
expect(resolveQuestionTool(tmp, 'render')).toBe(join(tmp, 'tools', 'questions', 'render.py'));
|
|
expect(resolveQuestionTool(tmp, 'bogus')).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('registerQCommand usage + dispatch', () => {
|
|
const saved = process.env['MOSAIC_BRAIN_HOME'];
|
|
afterEach(() => {
|
|
if (saved === undefined) delete process.env['MOSAIC_BRAIN_HOME'];
|
|
else process.env['MOSAIC_BRAIN_HOME'] = saved;
|
|
process.exitCode = undefined;
|
|
});
|
|
|
|
it('exit 2 with the subcommand list when no/unknown subcommand', async () => {
|
|
process.env['MOSAIC_BRAIN_HOME'] = mkdtempSync(join(tmpdir(), 'q-usage-'));
|
|
const program = new Command();
|
|
registerQCommand(program);
|
|
await program.parseAsync(['q'], { from: 'user' });
|
|
expect(process.exitCode).toBe(2);
|
|
process.exitCode = undefined;
|
|
await program.parseAsync(['q', 'bogus'], { from: 'user' });
|
|
expect(process.exitCode).toBe(2);
|
|
process.exitCode = undefined;
|
|
// Reserved property names must not leak through the record lookup.
|
|
await program.parseAsync(['q', 'toString'], { from: 'user' });
|
|
expect(process.exitCode).toBe(2);
|
|
});
|
|
|
|
it('execs the brain tool with pass-through args and exit code', async () => {
|
|
const tmp = mkdtempSync(join(tmpdir(), 'q-live-'));
|
|
process.env['MOSAIC_BRAIN_HOME'] = tmp;
|
|
mkdirSync(join(tmp, 'tools', 'questions'), { recursive: true });
|
|
const stub = join(tmp, 'tools', 'questions', 'q-new.sh');
|
|
writeFileSync(stub, '#!/usr/bin/env bash\necho "called with: $*"\nexit 7\n');
|
|
chmodSync(stub, 0o755);
|
|
|
|
const program = new Command();
|
|
registerQCommand(program);
|
|
await program.parseAsync(['q', 'new', '--slug', 'x', '--question', 'why'], { from: 'user' });
|
|
expect(process.exitCode).toBe(7);
|
|
});
|
|
});
|
|
|
|
describe('exitStatusFor (shared dispatch contract)', () => {
|
|
it('maps absent tool to 127', () => {
|
|
expect(exitStatusFor({ status: 0 }, false)).toBe(127);
|
|
});
|
|
it('passes tool status through', () => {
|
|
expect(exitStatusFor({ status: 7 }, true)).toBe(7);
|
|
});
|
|
it('maps signal death to 125', () => {
|
|
expect(exitStatusFor({ status: null }, true)).toBe(125);
|
|
});
|
|
});
|