feat(voyage)!: marketplace handoff — rename plugins/ultraplan-local to plugins/voyage [skip-docs]
Session 5 of voyage-rebrand (V6). Operator-authorized cross-plugin scope. - git mv plugins/ultraplan-local plugins/voyage (rename detected, history preserved) - .claude-plugin/marketplace.json: voyage entry replaces ultraplan-local - CLAUDE.md: voyage row in plugin list, voyage in design-system consumer list - README.md: bulk rename ultra*-local commands -> trek* commands; ultraplan-local refs -> voyage; type discriminators (type: trekbrief/trekreview); session-title pattern (voyage:<command>:<slug>); v4.0.0 release-note paragraph - plugins/voyage/.claude-plugin/plugin.json: homepage/repository URLs point to monorepo voyage path - plugins/voyage/verify.sh: drop URL whitelist exception (no longer needed) Closes voyage-rebrand. bash plugins/voyage/verify.sh PASS 7/7. npm test 361/361.
This commit is contained in:
parent
8f1bf9b7b4
commit
7a90d348ad
149 changed files with 26 additions and 33 deletions
127
plugins/voyage/examples/02-real-cli/tests/tally.test.mjs
Normal file
127
plugins/voyage/examples/02-real-cli/tests/tally.test.mjs
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { dirname, resolve } from 'node:path';
|
||||
|
||||
const here = dirname(fileURLToPath(import.meta.url));
|
||||
const TALLY = resolve(here, '..', 'tally.mjs');
|
||||
const SAMPLE = resolve(here, '..', 'fixtures', 'sample.txt');
|
||||
const POEM = resolve(here, '..', 'fixtures', 'poem.txt');
|
||||
|
||||
function run(...args) {
|
||||
return spawnSync('node', [TALLY, ...args], { encoding: 'utf8' });
|
||||
}
|
||||
|
||||
test('plain count: tally foo sample.txt prints 7', () => {
|
||||
const r = run('foo', SAMPLE);
|
||||
assert.equal(r.status, 0);
|
||||
assert.equal(r.stdout.trim(), '7');
|
||||
assert.equal(r.stderr, '');
|
||||
});
|
||||
|
||||
test('JSON output: tally --json foo sample.txt parses with count 7', () => {
|
||||
const r = run('--json', 'foo', SAMPLE);
|
||||
assert.equal(r.status, 0);
|
||||
const parsed = JSON.parse(r.stdout);
|
||||
assert.equal(parsed.count, 7);
|
||||
assert.equal(parsed.pattern, 'foo');
|
||||
assert.equal(parsed.flags.json, true);
|
||||
assert.equal(parsed.flags.ignoreCase, false);
|
||||
assert.equal(parsed.flags.lines, false);
|
||||
});
|
||||
|
||||
test('case-sensitive default: tally Foo sample.txt prints 1', () => {
|
||||
const r = run('Foo', SAMPLE);
|
||||
assert.equal(r.status, 0);
|
||||
assert.equal(r.stdout.trim(), '1');
|
||||
});
|
||||
|
||||
test('case-insensitive: tally -i Foo == tally -i foo (and exceeds case-sensitive)', () => {
|
||||
const ri1 = run('-i', 'Foo', SAMPLE);
|
||||
const ri2 = run('-i', 'foo', SAMPLE);
|
||||
const rcs = run('foo', SAMPLE);
|
||||
assert.equal(ri1.status, 0);
|
||||
assert.equal(ri2.status, 0);
|
||||
assert.equal(ri1.stdout, ri2.stdout);
|
||||
assert.ok(Number(ri1.stdout) > Number(rcs.stdout));
|
||||
});
|
||||
|
||||
test('--lines mode: tally --lines foo poem.txt prints 3 (not total occurrences 4)', () => {
|
||||
const lines = run('--lines', 'foo', POEM);
|
||||
const total = run('foo', POEM);
|
||||
assert.equal(lines.status, 0);
|
||||
assert.equal(total.status, 0);
|
||||
assert.equal(lines.stdout.trim(), '3');
|
||||
assert.equal(total.stdout.trim(), '4');
|
||||
});
|
||||
|
||||
test('flag in last position: tally foo sample.txt --json equals tally --json foo sample.txt', () => {
|
||||
const last = run('foo', SAMPLE, '--json');
|
||||
const first = run('--json', 'foo', SAMPLE);
|
||||
assert.equal(last.status, 0);
|
||||
assert.equal(first.status, 0);
|
||||
assert.equal(last.stdout, first.stdout);
|
||||
});
|
||||
|
||||
test('missing argument: tally foo exits 2 with stderr', () => {
|
||||
const r = run('foo');
|
||||
assert.equal(r.status, 2);
|
||||
assert.match(r.stderr, /^tally: /);
|
||||
assert.equal(r.stdout, '');
|
||||
});
|
||||
|
||||
test('unknown flag: tally --unknown foo sample.txt exits 2 with stderr', () => {
|
||||
const r = run('--unknown', 'foo', SAMPLE);
|
||||
assert.equal(r.status, 2);
|
||||
assert.match(r.stderr, /^tally: /);
|
||||
assert.equal(r.stdout, '');
|
||||
});
|
||||
|
||||
test('file not found: tally foo /does/not/exist exits 1 with stderr', () => {
|
||||
const r = run('foo', '/does/not/exist');
|
||||
assert.equal(r.status, 1);
|
||||
assert.match(r.stderr, /^tally: /);
|
||||
assert.equal(r.stdout, '');
|
||||
});
|
||||
|
||||
test('--help: stdout contains "Usage:", exit 0', () => {
|
||||
const r = run('--help');
|
||||
assert.equal(r.status, 0);
|
||||
assert.match(r.stdout, /Usage:/);
|
||||
assert.match(r.stdout, /--ignore-case/);
|
||||
});
|
||||
|
||||
// --- Tests for --regex / -r mode (added in plan step 4, Spor B B3) ---
|
||||
|
||||
test("--regex 'fo+' counts more matches than literal 'foo' (long form, exit 0)", () => {
|
||||
const literal = run('foo', SAMPLE);
|
||||
const regex = run('--regex', 'fo+', SAMPLE);
|
||||
assert.equal(literal.status, 0);
|
||||
assert.equal(regex.status, 0);
|
||||
assert.ok(Number(regex.stdout) >= Number(literal.stdout),
|
||||
`regex count (${regex.stdout.trim()}) should be >= literal count (${literal.stdout.trim()})`);
|
||||
});
|
||||
|
||||
test("-r short form equals --regex long form (same stdout)", () => {
|
||||
const short = run('-r', 'fo+', SAMPLE);
|
||||
const long = run('--regex', 'fo+', SAMPLE);
|
||||
assert.equal(short.status, 0);
|
||||
assert.equal(long.status, 0);
|
||||
assert.equal(short.stdout, long.stdout);
|
||||
});
|
||||
|
||||
test("--regex '[' exits 2 with stderr 'tally: invalid regex'", () => {
|
||||
const r = run('--regex', '[', SAMPLE);
|
||||
assert.equal(r.status, 2);
|
||||
assert.equal(r.stdout, '');
|
||||
assert.match(r.stderr, /^tally: invalid regex/);
|
||||
});
|
||||
|
||||
test("--json --regex 'fo+' includes flags.regex === true in output", () => {
|
||||
const r = run('--json', '--regex', 'fo+', SAMPLE);
|
||||
assert.equal(r.status, 0);
|
||||
const parsed = JSON.parse(r.stdout);
|
||||
assert.equal(parsed.flags.regex, true);
|
||||
assert.ok(typeof parsed.count === 'number' && parsed.count > 0);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue