95 lines
3.5 KiB
Python
95 lines
3.5 KiB
Python
#!/usr/bin/env python3
|
||
"""Ashtakavarga mathematical invariant tests."""
|
||
|
||
from __future__ import annotations
|
||
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
ROOT = Path(__file__).resolve().parents[1]
|
||
SCRIPTS = ROOT / "scripts"
|
||
if str(SCRIPTS) not in sys.path:
|
||
sys.path.insert(0, str(SCRIPTS))
|
||
|
||
from ashtakavarga import ( # noqa: E402
|
||
ALL_SOURCES,
|
||
BAV_TOTALS,
|
||
EXPECTED_SAV_TOTAL,
|
||
SEVEN_PLANETS,
|
||
SIGNS,
|
||
calc_ashtakavarga,
|
||
calc_prastara_av,
|
||
calc_yoga_pinda,
|
||
)
|
||
|
||
|
||
def _planet_signs(offset: int = 0, step: int = 1) -> dict[str, dict[str, str]]:
|
||
return {planet: {"sign": SIGNS[(offset + index * step) % 12]} for index, planet in enumerate(SEVEN_PLANETS)}
|
||
|
||
|
||
def test_ashtakavarga_totals_are_position_independent() -> None:
|
||
samples = [
|
||
(_planet_signs(offset=0, step=1), 0),
|
||
(_planet_signs(offset=2, step=3), 4),
|
||
(_planet_signs(offset=7, step=5), 11),
|
||
]
|
||
for planets, asc_sign_idx in samples:
|
||
result = calc_ashtakavarga(planets, asc_sign_idx)
|
||
|
||
assert result["sav"]["total"] == EXPECTED_SAV_TOTAL
|
||
assert result["sav"]["valid"] is True
|
||
assert result["sav"]["full_total_with_lagna"] == EXPECTED_SAV_TOTAL + BAV_TOTALS["Lagna"]
|
||
assert result["all_bav_valid"] is True
|
||
|
||
for planet in ALL_SOURCES:
|
||
assert result["bav"][planet]["total"] == BAV_TOTALS[planet]
|
||
assert result["bav"][planet]["valid"] is True
|
||
|
||
|
||
def test_ashtakavarga_output_contract() -> None:
|
||
planets = {planet: {"sign": SIGNS[index % 12]} for index, planet in enumerate(SEVEN_PLANETS)}
|
||
result = calc_ashtakavarga(planets, asc_sign_idx=0)
|
||
|
||
assert result["method"] == "Ashtakavarga八分法(BPHS/PVR书例校准v2.1)"
|
||
assert result["version"] == "2.1"
|
||
assert set(result["sav"]["scores"].keys()) == set(SIGNS)
|
||
assert len(result["house_scores"]) == 12
|
||
assert len(result["house_scores_full"]) == 12
|
||
|
||
|
||
def test_prastara_matrix_reconstructs_each_planets_bav() -> None:
|
||
planets = {planet: {"sign": SIGNS[(index * 2) % 12]} for index, planet in enumerate(SEVEN_PLANETS)}
|
||
result = calc_ashtakavarga(planets, asc_sign_idx=3)
|
||
pav = calc_prastara_av(planets, asc_sign_idx=3)
|
||
|
||
assert pav["all_valid"] is True
|
||
assert pav["matrix_shape"] == {"planets": 7, "signs": 12, "sources": 8}
|
||
|
||
for planet in SEVEN_PLANETS:
|
||
reconstructed = [0] * 12
|
||
for source in ALL_SOURCES:
|
||
for index, value in enumerate(pav["pav"][planet][source]):
|
||
reconstructed[index] += value
|
||
assert reconstructed == result["bav"][planet]["bindus"]
|
||
|
||
|
||
def test_yoga_pinda_is_first_class_contract() -> None:
|
||
planets = {planet: {"sign": SIGNS[(index * 3) % 12]} for index, planet in enumerate(SEVEN_PLANETS)}
|
||
result = calc_ashtakavarga(planets, asc_sign_idx=5)
|
||
yoga_pinda = calc_yoga_pinda(result["bav"], planets, asc_sign_idx=5)
|
||
|
||
assert yoga_pinda["method"] == "Yoga Pinda"
|
||
assert yoga_pinda["all_valid"] is True
|
||
assert yoga_pinda["summary"]["strongest_planet"] in SEVEN_PLANETS
|
||
assert yoga_pinda["summary"]["total_yoga_pinda"] == sum(
|
||
item["yoga_pinda"] for item in yoga_pinda["planets"].values()
|
||
)
|
||
|
||
for planet in SEVEN_PLANETS:
|
||
row = yoga_pinda["planets"][planet]
|
||
legacy = result["shodhya_pinda"][planet]
|
||
assert row["rashi_pinda"] == legacy["rashi_pinda"]
|
||
assert row["graha_pinda"] == legacy["graha_pinda"]
|
||
assert row["yoga_pinda"] == legacy["total_pinda"]
|
||
assert row["bindu_at_own_sign"] == legacy["bindu_at_own_sign"]
|