import { describe, it, expect } from 'vitest' import { ZiweiService } from '@/services/ziweiService' import { EarthlyBranch, HeavenlyStem, PalaceType } from '@/algorithms/enums' const ZIWEI_FORMULA_REFERENCE = '紫微斗数安星诀:命宫=14-月支-时支,身宫=2+月支+时支' const GANZHI_CALENDAR_REFERENCE = '万年历:年干支=(年-4)%10/%12,以甲子为起点' const CROSS_VALIDATION_DATA = [ { birthTime: '1990-01-15T10:00:00', gender: 'male' as const, yearGanZhi: '庚午', expectedYearStem: HeavenlyStem.GENG, expectedYearBranch: EarthlyBranch.WU, expectedMonthBranch: EarthlyBranch.YIN, expectedHourBranch: EarthlyBranch.SI, expectedMingGongBranch: EarthlyBranch.CHEN, expectedShenGongBranch: EarthlyBranch.XU, }, { birthTime: '1985-06-20T14:00:00', gender: 'female' as const, yearGanZhi: '乙丑', expectedYearStem: HeavenlyStem.YI, expectedYearBranch: EarthlyBranch.CHOU, expectedMonthBranch: EarthlyBranch.WEI, expectedHourBranch: EarthlyBranch.WEI, expectedMingGongBranch: EarthlyBranch.YOU, expectedShenGongBranch: EarthlyBranch.SI, }, { birthTime: '2000-12-01T06:00:00', gender: 'male' as const, yearGanZhi: '庚辰', expectedYearStem: HeavenlyStem.GENG, expectedYearBranch: EarthlyBranch.CHEN, expectedMonthBranch: EarthlyBranch.CHOU, expectedHourBranch: EarthlyBranch.MAO, expectedMingGongBranch: EarthlyBranch.WEI, expectedShenGongBranch: EarthlyBranch.WEI, }, { birthTime: '1975-03-08T22:00:00', gender: 'female' as const, yearGanZhi: '乙卯', expectedYearStem: HeavenlyStem.YI, expectedYearBranch: EarthlyBranch.MAO, expectedMonthBranch: EarthlyBranch.CHEN, expectedHourBranch: EarthlyBranch.HAI, expectedMingGongBranch: EarthlyBranch.SHEN, expectedShenGongBranch: EarthlyBranch.WU, }, { birthTime: '1995-09-30T18:00:00', gender: 'male' as const, yearGanZhi: '乙亥', expectedYearStem: HeavenlyStem.YI, expectedYearBranch: EarthlyBranch.HAI, expectedMonthBranch: EarthlyBranch.XU, expectedHourBranch: EarthlyBranch.YOU, expectedMingGongBranch: EarthlyBranch.CHEN, expectedShenGongBranch: EarthlyBranch.XU, }, ] describe('紫微算法交叉验证', () => { const ziweiService = new ZiweiService() describe('年干支计算验证', () => { for (const data of CROSS_VALIDATION_DATA) { it(`${data.birthTime} 年干支应为${data.yearGanZhi}`, async () => { const chart = await ziweiService.generateChart({ birthTime: data.birthTime, gender: data.gender, timezone: 'Asia/Shanghai', }) expect(chart.birthInfo.yearStem).toBe(data.expectedYearStem) expect(chart.birthInfo.yearBranch).toBe(data.expectedYearBranch) }) } }) describe('月支映射验证', () => { for (const data of CROSS_VALIDATION_DATA) { it(`${data.birthTime} 月支应为${EarthlyBranch.name(data.expectedMonthBranch)}`, async () => { const chart = await ziweiService.generateChart({ birthTime: data.birthTime, gender: data.gender, timezone: 'Asia/Shanghai', }) expect(chart.birthInfo.monthBranch).toBe(data.expectedMonthBranch) }) } }) describe('时支映射验证', () => { for (const data of CROSS_VALIDATION_DATA) { it(`${data.birthTime} 时支应为${EarthlyBranch.name(data.expectedHourBranch)}`, async () => { const chart = await ziweiService.generateChart({ birthTime: data.birthTime, gender: data.gender, timezone: 'Asia/Shanghai', }) expect(chart.birthInfo.hourBranch).toBe(data.expectedHourBranch) }) } }) describe('命宫计算验证', () => { for (const data of CROSS_VALIDATION_DATA) { it(`${data.birthTime}(${data.gender}) 命宫地支应为${EarthlyBranch.name(data.expectedMingGongBranch)}`, async () => { const chart = await ziweiService.generateChart({ birthTime: data.birthTime, gender: data.gender, timezone: 'Asia/Shanghai', }) expect(chart.mingGongBranch).toBe(data.expectedMingGongBranch) }) } }) describe('身宫计算验证', () => { for (const data of CROSS_VALIDATION_DATA) { it(`${data.birthTime}(${data.gender}) 身宫地支应为${EarthlyBranch.name(data.expectedShenGongBranch)}`, async () => { const chart = await ziweiService.generateChart({ birthTime: data.birthTime, gender: data.gender, timezone: 'Asia/Shanghai', }) expect(chart.shenGongBranch).toBe(data.expectedShenGongBranch) }) } }) describe('命宫公式独立性验证', () => { for (const data of CROSS_VALIDATION_DATA) { it(`命宫=14-月支-时支 验证 ${data.birthTime}`, async () => { const chart = await ziweiService.generateChart({ birthTime: data.birthTime, gender: data.gender, timezone: 'Asia/Shanghai', }) const monthIndex = EarthlyBranch.index(chart.birthInfo.monthBranch) const hourIndex = EarthlyBranch.index(chart.birthInfo.hourBranch) let expectedMingGongIndex = 14 - monthIndex - hourIndex while (expectedMingGongIndex <= 0) expectedMingGongIndex += 12 if (expectedMingGongIndex > 12) expectedMingGongIndex -= 12 expect(EarthlyBranch.index(chart.mingGongBranch)).toBe(expectedMingGongIndex) }) it(`身宫=2+月支+时支 验证 ${data.birthTime}`, async () => { const chart = await ziweiService.generateChart({ birthTime: data.birthTime, gender: data.gender, timezone: 'Asia/Shanghai', }) const monthIndex = EarthlyBranch.index(chart.birthInfo.monthBranch) const hourIndex = EarthlyBranch.index(chart.birthInfo.hourBranch) let expectedShenGongIndex = 2 + monthIndex + hourIndex while (expectedShenGongIndex > 12) expectedShenGongIndex -= 12 expect(EarthlyBranch.index(chart.shenGongBranch)).toBe(expectedShenGongIndex) }) } }) describe('盘面结构完整性验证', () => { it('应生成12个宫位', async () => { const chart = await ziweiService.generateChart({ birthTime: '1990-01-15T10:00:00', gender: 'male', timezone: 'Asia/Shanghai', }) expect(chart.palaces.length).toBe(12) }) it('每个宫位应有宫型、地支和主星', async () => { const chart = await ziweiService.generateChart({ birthTime: '1990-01-15T10:00:00', gender: 'male', timezone: 'Asia/Shanghai', }) for (const palace of chart.palaces) { expect(palace.palaceType).toBeTruthy() expect(palace.earthlyBranch).toBeTruthy() expect(Array.isArray(palace.majorStars)).toBe(true) } }) it('命宫应存在于盘面中', async () => { const chart = await ziweiService.generateChart({ birthTime: '1990-01-15T10:00:00', gender: 'male', timezone: 'Asia/Shanghai', }) const mingPalace = chart.palaces.find(p => p.palaceType === PalaceType.MING) expect(mingPalace).toBeDefined() expect(mingPalace!.earthlyBranch).toBe(chart.mingGongBranch) }) it('三方四正应包含四个宫位且命宫正确', async () => { const chart = await ziweiService.generateChart({ birthTime: '1990-01-15T10:00:00', gender: 'male', timezone: 'Asia/Shanghai', }) expect(chart.sanFangSiZheng).toBeDefined() expect(chart.sanFangSiZheng!.mingGong.palaceType).toBe(PalaceType.MING) expect(chart.sanFangSiZheng!.caiBoGong).toBeDefined() expect(chart.sanFangSiZheng!.guanLuGong).toBeDefined() expect(chart.sanFangSiZheng!.qianYiGong).toBeDefined() }) it('三方四正各宫地支应满足对宫关系', async () => { const chart = await ziweiService.generateChart({ birthTime: '1990-01-15T10:00:00', gender: 'male', timezone: 'Asia/Shanghai', }) const sfz = chart.sanFangSiZheng! const mingIndex = EarthlyBranch.index(sfz.mingGong.earthlyBranch) const caiBoIndex = EarthlyBranch.index(sfz.caiBoGong.earthlyBranch) const guanLuIndex = EarthlyBranch.index(sfz.guanLuGong.earthlyBranch) const qianYiIndex = EarthlyBranch.index(sfz.qianYiGong.earthlyBranch) let expectedCaiBo = mingIndex + 5 if (expectedCaiBo > 12) expectedCaiBo -= 12 let expectedGuanLu = mingIndex + 10 if (expectedGuanLu > 12) expectedGuanLu -= 12 let expectedQianYi = mingIndex + 6 if (expectedQianYi > 12) expectedQianYi -= 12 expect(caiBoIndex).toBe(expectedCaiBo) expect(guanLuIndex).toBe(expectedGuanLu) expect(qianYiIndex).toBe(expectedQianYi) }) }) describe('确定性验证', () => { it('相同参数应产生完全相同的盘', async () => { const params = { birthTime: '1990-01-15T10:00:00', gender: 'male' as const, timezone: 'Asia/Shanghai', } const a = await ziweiService.generateChart(params) const b = await ziweiService.generateChart(params) expect(a.mingGongBranch).toBe(b.mingGongBranch) expect(a.shenGongBranch).toBe(b.shenGongBranch) expect(a.palaces.length).toBe(b.palaces.length) expect(a.overallLuck).toBe(b.overallLuck) }) }) describe('边界条件验证', () => { it('子时(0点)应映射为ZI', async () => { const chart = await ziweiService.generateChart({ birthTime: '1990-01-15T00:00:00', gender: 'male', timezone: 'Asia/Shanghai', }) expect(chart.birthInfo.hourBranch).toBe(EarthlyBranch.ZI) }) it('子时(1点)应映射为ZI', async () => { const chart = await ziweiService.generateChart({ birthTime: '1990-01-15T01:00:00', gender: 'male', timezone: 'Asia/Shanghai', }) expect(chart.birthInfo.hourBranch).toBe(EarthlyBranch.ZI) }) it('亥时(23点)应映射为HAI', async () => { const chart = await ziweiService.generateChart({ birthTime: '1990-01-15T23:00:00', gender: 'male', timezone: 'Asia/Shanghai', }) expect(chart.birthInfo.hourBranch).toBe(EarthlyBranch.HAI) }) it('1月应映射为YIN', async () => { const chart = await ziweiService.generateChart({ birthTime: '1990-01-15T10:00:00', gender: 'male', timezone: 'Asia/Shanghai', }) expect(chart.birthInfo.monthBranch).toBe(EarthlyBranch.YIN) }) it('12月应映射为CHOU', async () => { const chart = await ziweiService.generateChart({ birthTime: '1990-12-15T10:00:00', gender: 'male', timezone: 'Asia/Shanghai', }) expect(chart.birthInfo.monthBranch).toBe(EarthlyBranch.CHOU) }) }) })