import test from 'node:test'; import assert from 'node:assert/strict'; import { JIAOHUI, GATE, NVXING_ENGINE, jiaohuiGate, jiaohuiEligible, buildJiaohui } from '../src/jiaohui.js'; import { getNvxing } from '../src/nvxing.js'; test('每个交会点的 guanId 都真实指向那位女性 arc 里的一道关', () => { for (const [id, j] of Object.entries(JIAOHUI)) { const w = getNvxing(id); assert.ok(w, `${id} 应是真实的她传女性`); assert.ok(w.arc.some((g) => g.id === j.guanId), `${id} 的交会点 ${j.guanId} 应在其 arc 里`); assert.ok(j.male?.name && j.male?.seat, `${id} 应有男座`); assert.ok(GATE[j.gate], `${id} 的 gate=${j.gate} 应是合法档`); assert.ok(j.ersheng && j.together, `${id} 应有二圣同框与共写文案`); } }); test('杨丽华不设交会(一生无共治·诚实缺席)', () => { assert.ok(!JIAOHUI.yanglihua, '杨丽华不应在交会目录里'); assert.equal(jiaohuiGate('yanglihua'), null); }); test('只有 7 位女性映射到引擎朝(其余诚实标暂无)', () => { const withEngine = Object.keys(JIAOHUI).filter((id) => NVXING_ENGINE[id]); assert.equal(withEngine.length, 7); assert.deepEqual(new Set(withEngine), new Set(['wuzetian', 'luhou', 'dengsui', 'jiananfeng', 'liue', 'qinliangyu', 'xiaochuo'])); }); test('资格判定:够到顶/逼近顶=放行,差得远=挡+算出还差几级', () => { // 武则天 gate=jun(slack0):必须 atCeiling 或 tier>=ceiling const wzt = (stat) => jiaohuiEligible('wuzetian', stat); assert.equal(wzt({ tier: 5, ceilingTier: 5 }).eligible, true, 'tier到顶应放行'); assert.equal(wzt({ tier: 3, ceilingTier: 5 }).eligible, false, 'tier离顶2级(jun不容)应挡'); assert.equal(wzt({ tier: 3, ceilingTier: 5 }).short, 2, '应算出还差2级'); assert.equal(wzt({ tier: 2, ceilingTier: 5, atCeiling: true }).eligible, true, 'atCeiling直接放行'); // 秦良玉 gate=jiang(slack1·明有引擎):差1级仍放行,差2级挡 assert.equal(jiaohuiEligible('qinliangyu', { tier: 4, ceilingTier: 5 }).eligible, true, '将帅档差1级仍放行'); assert.equal(jiaohuiEligible('qinliangyu', { tier: 3, ceilingTier: 5 }).eligible, false, '将帅档差2级应挡'); }); test('引擎未及/无分身:computable=false,不判够不够(诚实)', () => { assert.equal(jiaohuiEligible('dugujialuo', { tier: 5, ceilingTier: 5 }).computable, false, '隋无引擎→算不出'); assert.equal(jiaohuiEligible('dugujialuo', { tier: 5, ceilingTier: 5 }).reason, 'engine-none'); assert.equal(jiaohuiEligible('wuzetian', null).computable, false, '无分身→算不出'); assert.equal(jiaohuiEligible('wuzetian', null).reason, 'no-twin'); }); test('buildJiaohui:复用她传那道关(双证),男方选择只入合传不改史', () => { const s = buildJiaohui('wuzetian', { hostName: '张三', hostPick: 'go' }); assert.equal(s.woman.name, '武则天'); assert.equal(s.guan.id, 'ersheng'); assert.ok(/《.+》/.test(s.guan.cite), '交会关应带可查 cite'); assert.ok(s.guan.real, '应有她真实那步'); assert.equal(s.host.pick, 'go'); assert.ok(s.hezhuan.line.includes('武则天') && s.hezhuan.line.includes('唐高宗'), '合传应含双方'); assert.equal(typeof s.hezhuan.sameStep, 'boolean'); // 未选时无 host/hezhuan assert.equal(buildJiaohui('wuzetian', {}).host, null); });