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.
56 lines
2.2 KiB
JavaScript
56 lines
2.2 KiB
JavaScript
import { test } from 'node:test';
|
||
import { strict as assert } from 'node:assert';
|
||
import { jaccardSimilarity, meetsThreshold } from '../../lib/parsers/jaccard.mjs';
|
||
|
||
test('jaccardSimilarity — identical sets → 1.0', () => {
|
||
assert.equal(jaccardSimilarity(['a', 'b', 'c'], ['a', 'b', 'c']), 1.0);
|
||
});
|
||
|
||
test('jaccardSimilarity — disjoint sets → 0.0', () => {
|
||
assert.equal(jaccardSimilarity(['a', 'b'], ['c', 'd']), 0.0);
|
||
});
|
||
|
||
test('jaccardSimilarity — partial overlap [a,b,c] vs [b,c,d] → 0.5', () => {
|
||
assert.equal(jaccardSimilarity(['a', 'b', 'c'], ['b', 'c', 'd']), 0.5);
|
||
});
|
||
|
||
test('jaccardSimilarity — both empty → 1.0', () => {
|
||
assert.equal(jaccardSimilarity([], []), 1.0);
|
||
});
|
||
|
||
test('jaccardSimilarity — one empty → 0.0', () => {
|
||
assert.equal(jaccardSimilarity([], ['a']), 0.0);
|
||
assert.equal(jaccardSimilarity(['a'], []), 0.0);
|
||
});
|
||
|
||
test('jaccardSimilarity — duplicates deduplicated within each set', () => {
|
||
// [a,a,b] dedup → {a,b}; [a,b,b] dedup → {a,b}; identical → 1.0
|
||
assert.equal(jaccardSimilarity(['a', 'a', 'b'], ['a', 'b', 'b']), 1.0);
|
||
});
|
||
|
||
test('jaccardSimilarity — fixture sets {α..ε} vs {α..ζ} → 0.833 (SC4 anchor)', () => {
|
||
// SC4 fixture math: A=5 IDs, B=A∪{ζ}=6 IDs, intersection=5, union=6 → 5/6
|
||
const A = ['α', 'β', 'γ', 'δ', 'ε'];
|
||
const B = ['α', 'β', 'γ', 'δ', 'ε', 'ζ'];
|
||
const sim = jaccardSimilarity(A, B);
|
||
assert.ok(Math.abs(sim - 5 / 6) < 1e-9);
|
||
assert.ok(sim >= 0.70); // SC4 threshold
|
||
});
|
||
|
||
test('jaccardSimilarity — non-array input throws TypeError', () => {
|
||
assert.throws(() => jaccardSimilarity('a', ['b']), TypeError);
|
||
assert.throws(() => jaccardSimilarity(['a'], null), TypeError);
|
||
});
|
||
|
||
test('meetsThreshold — boundary 0.699 → false, 0.700 → true', () => {
|
||
assert.equal(meetsThreshold(0.699, 0.7), false);
|
||
assert.equal(meetsThreshold(0.7, 0.7), true);
|
||
assert.equal(meetsThreshold(0.71, 0.7), true);
|
||
});
|
||
|
||
test('meetsThreshold — non-finite or non-number → false', () => {
|
||
assert.equal(meetsThreshold(NaN, 0.7), false);
|
||
assert.equal(meetsThreshold(Infinity, 0.7), false);
|
||
assert.equal(meetsThreshold('0.8', 0.7), false);
|
||
assert.equal(meetsThreshold(0.8, null), false);
|
||
});
|