202 lines
7.1 KiB
Python
202 lines
7.1 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
from core.divination.derivation import (
|
||
|
|
_get_kong_wang,
|
||
|
|
_resolve_liu_shou,
|
||
|
|
_wu_xing_status,
|
||
|
|
derive_divination,
|
||
|
|
)
|
||
|
|
from schemas.domain.divination import DivinationPayload, DivinationMethod, YaoType
|
||
|
|
|
||
|
|
|
||
|
|
class TestKongWangCalculation:
|
||
|
|
def test_kong_wang_jia_zi(self) -> None:
|
||
|
|
assert _get_kong_wang("甲子") == "戌亥"
|
||
|
|
|
||
|
|
def test_kong_wang_jia_xu(self) -> None:
|
||
|
|
assert _get_kong_wang("甲戌") == "申酉"
|
||
|
|
|
||
|
|
def test_kong_wang_jia_shen(self) -> None:
|
||
|
|
assert _get_kong_wang("甲申") == "午未"
|
||
|
|
|
||
|
|
def test_kong_wang_jia_wu(self) -> None:
|
||
|
|
assert _get_kong_wang("甲午") == "辰巳"
|
||
|
|
|
||
|
|
def test_kong_wang_jia_chen(self) -> None:
|
||
|
|
assert _get_kong_wang("甲辰") == "寅卯"
|
||
|
|
|
||
|
|
def test_kong_wang_jia_yin(self) -> None:
|
||
|
|
assert _get_kong_wang("甲寅") == "子丑"
|
||
|
|
|
||
|
|
|
||
|
|
class TestLiuShouCalculation:
|
||
|
|
def test_liu_shou_jia_yi(self) -> None:
|
||
|
|
assert _resolve_liu_shou("甲") == ("龙", "雀", "勾", "蛇", "虎", "玄")
|
||
|
|
assert _resolve_liu_shou("乙") == ("龙", "雀", "勾", "蛇", "虎", "玄")
|
||
|
|
|
||
|
|
def test_liu_shou_bing_ding(self) -> None:
|
||
|
|
assert _resolve_liu_shou("丙") == ("雀", "勾", "蛇", "虎", "玄", "龙")
|
||
|
|
assert _resolve_liu_shou("丁") == ("雀", "勾", "蛇", "虎", "玄", "龙")
|
||
|
|
|
||
|
|
def test_liu_shou_wu(self) -> None:
|
||
|
|
assert _resolve_liu_shou("戊") == ("勾", "蛇", "虎", "玄", "龙", "雀")
|
||
|
|
|
||
|
|
def test_liu_shou_ji(self) -> None:
|
||
|
|
assert _resolve_liu_shou("己") == ("蛇", "虎", "玄", "龙", "雀", "勾")
|
||
|
|
|
||
|
|
def test_liu_shou_geng_xin(self) -> None:
|
||
|
|
assert _resolve_liu_shou("庚") == ("虎", "玄", "龙", "雀", "勾", "蛇")
|
||
|
|
assert _resolve_liu_shou("辛") == ("虎", "玄", "龙", "雀", "勾", "蛇")
|
||
|
|
|
||
|
|
def test_liu_shou_ren_gui(self) -> None:
|
||
|
|
assert _resolve_liu_shou("壬") == ("玄", "龙", "雀", "勾", "蛇", "虎")
|
||
|
|
assert _resolve_liu_shou("癸") == ("玄", "龙", "雀", "勾", "蛇", "虎")
|
||
|
|
|
||
|
|
|
||
|
|
class TestWuXingStatus:
|
||
|
|
def test_wood_wang_in_yin_mao(self) -> None:
|
||
|
|
assert _wu_xing_status("寅", "木") == "旺"
|
||
|
|
assert _wu_xing_status("卯", "木") == "旺"
|
||
|
|
|
||
|
|
def test_fire_wang_in_si_wu(self) -> None:
|
||
|
|
assert _wu_xing_status("巳", "火") == "旺"
|
||
|
|
assert _wu_xing_status("午", "火") == "旺"
|
||
|
|
|
||
|
|
def test_metal_wang_in_shen_you(self) -> None:
|
||
|
|
assert _wu_xing_status("申", "金") == "旺"
|
||
|
|
assert _wu_xing_status("酉", "金") == "旺"
|
||
|
|
|
||
|
|
def test_water_wang_in_hai_zi(self) -> None:
|
||
|
|
assert _wu_xing_status("亥", "水") == "旺"
|
||
|
|
assert _wu_xing_status("子", "水") == "旺"
|
||
|
|
|
||
|
|
def test_earth_wang_in_chen_wei_chou_xu(self) -> None:
|
||
|
|
assert _wu_xing_status("辰", "土") == "旺"
|
||
|
|
assert _wu_xing_status("未", "土") == "旺"
|
||
|
|
assert _wu_xing_status("戌", "土") == "旺"
|
||
|
|
assert _wu_xing_status("丑", "土") == "旺"
|
||
|
|
|
||
|
|
|
||
|
|
class TestKongWangFromDayOnly:
|
||
|
|
def test_kong_wang_only_from_day_gan_zhi(self) -> None:
|
||
|
|
payload = DivinationPayload(
|
||
|
|
divinationMethod=DivinationMethod.MANUAL,
|
||
|
|
questionType="测试",
|
||
|
|
question="测试空亡仅从日柱",
|
||
|
|
divinationTimeIso="2025-01-15T12:00:00+08:00",
|
||
|
|
yaoLines=[
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
],
|
||
|
|
)
|
||
|
|
result = derive_divination(payload)
|
||
|
|
|
||
|
|
assert result.ganzhi.day_kong_wang == "午未"
|
||
|
|
assert result.ganzhi.time_kong_wang == "戌亥"
|
||
|
|
|
||
|
|
kong_wang_yao = [s for s in result.special_status if "旬空" in s]
|
||
|
|
for status in kong_wang_yao:
|
||
|
|
if "午" in status or "未" in status:
|
||
|
|
pass
|
||
|
|
else:
|
||
|
|
assert "戌" not in status
|
||
|
|
assert "亥" not in status
|
||
|
|
|
||
|
|
|
||
|
|
class TestAnDongLogic:
|
||
|
|
def test_an_dong_wang_xiang_ri_chong(self) -> None:
|
||
|
|
payload = DivinationPayload(
|
||
|
|
divinationMethod=DivinationMethod.MANUAL,
|
||
|
|
questionType="测试",
|
||
|
|
question="测试暗动",
|
||
|
|
divinationTimeIso="2025-05-15T12:00:00+08:00",
|
||
|
|
yaoLines=[
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
],
|
||
|
|
)
|
||
|
|
result = derive_divination(payload)
|
||
|
|
|
||
|
|
an_dong_status = [s for s in result.special_status if "暗动" in s]
|
||
|
|
for status in an_dong_status:
|
||
|
|
assert "旺相" in status or "日冲" in status
|
||
|
|
|
||
|
|
def test_changing_yao_not_marked_as_kong_wang(self) -> None:
|
||
|
|
payload = DivinationPayload(
|
||
|
|
divinationMethod=DivinationMethod.MANUAL,
|
||
|
|
questionType="测试",
|
||
|
|
question="测试动爻不标空亡",
|
||
|
|
divinationTimeIso="2025-01-15T12:00:00+08:00",
|
||
|
|
yaoLines=[
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.LAO_YANG,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
],
|
||
|
|
)
|
||
|
|
result = derive_divination(payload)
|
||
|
|
|
||
|
|
for yao in result.yao_info_list:
|
||
|
|
if yao.is_changing:
|
||
|
|
for status in result.special_status:
|
||
|
|
if f"第{yao.position}爻" in status:
|
||
|
|
assert "旬空" not in status
|
||
|
|
|
||
|
|
|
||
|
|
class TestYuePoLogic:
|
||
|
|
def test_yue_po_independently_marked(self) -> None:
|
||
|
|
payload = DivinationPayload(
|
||
|
|
divinationMethod=DivinationMethod.MANUAL,
|
||
|
|
questionType="测试",
|
||
|
|
question="测试月破",
|
||
|
|
divinationTimeIso="2025-06-15T12:00:00+08:00",
|
||
|
|
yaoLines=[
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YIN,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
],
|
||
|
|
)
|
||
|
|
result = derive_divination(payload)
|
||
|
|
|
||
|
|
yue_po_status = [s for s in result.special_status if "月破" in s]
|
||
|
|
for status in yue_po_status:
|
||
|
|
assert "月破" in status
|
||
|
|
assert "暗动" not in status
|
||
|
|
|
||
|
|
|
||
|
|
class TestWangBuWeiKong:
|
||
|
|
def test_wang_xiang_yao_not_marked_as_kong_wang(self) -> None:
|
||
|
|
payload = DivinationPayload(
|
||
|
|
divinationMethod=DivinationMethod.MANUAL,
|
||
|
|
questionType="测试",
|
||
|
|
question="测试旺不为空",
|
||
|
|
divinationTimeIso="2025-01-15T12:00:00+08:00",
|
||
|
|
yaoLines=[
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
YaoType.SHAO_YANG,
|
||
|
|
],
|
||
|
|
)
|
||
|
|
result = derive_divination(payload)
|
||
|
|
|
||
|
|
for status in result.special_status:
|
||
|
|
if "旬空" in status:
|
||
|
|
if "丑" in status or "土" in status:
|
||
|
|
assert "旬空" not in status or "旺" not in status
|