Files
everything-is-suitable/everything-is-suitable-uniapp/src/algorithms/__tests__/cross-validation/ziwei-cross-validation.test.ts
T
zhangxiang 0f8b29874f chore: 清理旧测试基础设施并添加新测试框架
- 清理废弃的 CI/CD 工作流文件与 dogfood 输出
- 添加 vitest 测试环境配置(mocks、setup 文件)
- 添加算法、服务、页面、工具类的单元测试
- 更新 vitest 配置、依赖与文档
2026-08-12 18:53:15 +08:00

305 lines
11 KiB
TypeScript

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)
})
})
})