"""Walidacja silnika własnego względem wyroczni (LOG-01 + LOG-25). Porównujemy pozycje policzone Skyfieldem ze znanymi wartościami Swiss Ephemeris (astro.com) dla horoskopu referencyjnego. To dokładnie mechanizm LOG-25 — tyle że wyrocznią są tu zapisane wcześniej wartości referencyjne zamiast żywej usługi swisseph. Tolerancja 2' (120") z zapasem na różnicę barycentrum/centrum planety. """ from app.engine.compare import compare_positions from app.engine.models import ObjectPosition # obiekt -> (długość absolutna w stopniach, retrogradacja) — Swiss Ephemeris / astro.com REFERENCE = { "Sun": (40.139167, False), # Tau 10°08'21" "Moon": (30.551389, False), # Tau 0°33'05" "Mercury": (27.383889, True), # Ari 27°23'02" Rx "Venus": (27.676944, False), # Ari 27°40'37" "Mars": (234.541111, True), # Sco 24°32'28" Rx "Jupiter": (282.961667, True), # Cap 12°57'42" Rx "Saturn": (223.310833, True), # Sco 13°18'39" Rx "Uranus": (252.813333, True), # Sag 12°48'48" Rx "Neptune": (271.220833, True), # Cap 1°13'15" Rx "Pluto": (210.478889, True), # Sco 0°28'44" Rx } TOLERANCE_ARCSEC = 120.0 def _reference_positions(): return [ ObjectPosition(name, lon, 0.0, (-1.0 if retro else 1.0), retro) for name, (lon, retro) in REFERENCE.items() ] def test_positions_match_swisseph_reference(own_engine, reference_moment): got = own_engine.positions(reference_moment) report = compare_positions(got, _reference_positions(), lon_tol_arcsec=TOLERANCE_ARCSEC) assert report.ok, report.summary() def test_retrograde_flags_match(own_engine, reference_moment): got = {p.name: p for p in own_engine.positions(reference_moment)} for name, (_lon, retro) in REFERENCE.items(): assert got[name].retrograde == retro, f"{name}: kierunek niezgodny"