283 lines
12 KiB
Python
283 lines
12 KiB
Python
#!/usr/bin/env python3
|
|
"""Tests for tajika.py — Varshaphala annual chart, Tajika Yogas, Muntha."""
|
|
|
|
from __future__ import annotations
|
|
import sys, os, pytest
|
|
from datetime import datetime
|
|
|
|
SCRIPTS = os.path.join(os.path.dirname(__file__), '..', 'scripts')
|
|
if SCRIPTS not in sys.path:
|
|
sys.path.insert(0, SCRIPTS)
|
|
|
|
from tajika import (
|
|
calc_muntha, calc_year_lord, calc_mudda_dasha,
|
|
calc_tri_pataka, calc_tajika_yogas, detect_tajika_yogas,
|
|
detect_vedha, calc_all_sahams, calc_tajika_strength_layers, _is_faster,
|
|
SAHAM_RULES_PATH,
|
|
SIGNS, SIGN_LORDS,
|
|
)
|
|
|
|
# ── Muntha Tests ────────────────────────────────────────────────────
|
|
|
|
class TestMuntha:
|
|
def test_muntha_at_birth_age0(self):
|
|
result = calc_muntha(0, 0) # Aries asc, age 0
|
|
assert result['muntha_sign'] == 'Aries'
|
|
|
|
def test_muntha_advances_one_per_year(self):
|
|
result = calc_muntha(0, 1) # Aries + 1 year = Taurus
|
|
assert result['muntha_sign'] == 'Taurus'
|
|
|
|
def test_muntha_wraps_12(self):
|
|
result = calc_muntha(0, 12) # Back to Aries
|
|
assert result['muntha_sign'] == 'Aries'
|
|
|
|
def test_muntha_lord_correct(self):
|
|
result = calc_muntha(0, 1) # Taurus
|
|
assert result['muntha_lord'] == 'Venus'
|
|
|
|
def test_muntha_interpretation_exists(self):
|
|
result = calc_muntha(5, 10)
|
|
assert 'interpretation' in result
|
|
assert len(result['interpretation']) > 0
|
|
|
|
@pytest.mark.parametrize("asc_idx,age,expected_sign_idx",
|
|
[(0, 5, 5), (3, 7, 10), (11, 1, 0)])
|
|
def test_muntha_parametrized(self, asc_idx, age, expected_sign_idx):
|
|
result = calc_muntha(asc_idx, age)
|
|
assert result['muntha_sign_idx'] == expected_sign_idx
|
|
|
|
|
|
# ── Year Lord Tests ─────────────────────────────────────────────────
|
|
|
|
class TestYearLord:
|
|
def test_year_lord_matches_muntha_lord(self):
|
|
result = calc_year_lord(0, 1) # Taurus → Venus
|
|
assert result['year_lord'] == 'Venus'
|
|
|
|
def test_auxiliary_lords_present(self):
|
|
result = calc_year_lord(0, 5)
|
|
assert len(result['auxiliary_lords']) == 4
|
|
|
|
def test_year_theme_exists(self):
|
|
result = calc_year_lord(0, 5)
|
|
assert 'year_theme' in result
|
|
assert len(result['year_theme']) > 0
|
|
|
|
|
|
# ── Mudda Dasha Tests ──────────────────────────────────────────────
|
|
|
|
class TestMuddaDasha:
|
|
def test_starts_with_varsha_lord(self):
|
|
result = calc_mudda_dasha(0, 'Jupiter', 6)
|
|
assert result['dasha_sequence'][0]['lord'] == 'Jupiter'
|
|
|
|
def test_total_months_twelve(self):
|
|
result = calc_mudda_dasha(0, 'Sun', 1)
|
|
total = sum(d['months'] for d in result['dasha_sequence'])
|
|
assert abs(total - 12.0) < 0.5
|
|
|
|
def test_all_9_planets_covered(self):
|
|
result = calc_mudda_dasha(0, 'Jupiter', 1)
|
|
assert len(result['dasha_sequence']) <= 9
|
|
|
|
|
|
# ── Tri-Pataka Tests ───────────────────────────────────────────────
|
|
|
|
class TestTriPataka:
|
|
def test_all_strong_excellent(self):
|
|
# Put all lords in kendra houses from muntha
|
|
planet_lons = {
|
|
'Jupiter': 90.0, 'Saturn': 90.0, # Same sign as muntha = kendra
|
|
}
|
|
result = calc_tri_pataka(planet_lons, 'Jupiter', 3)
|
|
assert result['verdict'] in ('excellent', 'mixed', 'challenging')
|
|
|
|
def test_verdict_values(self):
|
|
planet_lons = {'Sun': 45.0, 'Moon': 135.0}
|
|
result = calc_tri_pataka(planet_lons, 'Sun', 0)
|
|
assert result['verdict'] in ('excellent', 'mixed', 'challenging')
|
|
|
|
def test_three_components_present(self):
|
|
planet_lons = {'Sun': 90.0, 'Moon': 180.0, 'Jupiter': 270.0}
|
|
result = calc_tri_pataka(planet_lons, 'Jupiter', 0)
|
|
assert 'dasha_lord' in result
|
|
assert 'muntha_lord' in result
|
|
assert 'year_lord' in result
|
|
|
|
|
|
# ── Harsha / Panchavargiya Bala Tests ─────────────────────────────
|
|
|
|
class TestTajikaStrengthLayers:
|
|
def test_harsha_and_panchavargiya_strength_layers(self):
|
|
planet_lons = {
|
|
'Sun': 10.0,
|
|
'Moon': 45.0,
|
|
'Mars': 92.0,
|
|
'Mercury': 152.0,
|
|
'Jupiter': 244.0,
|
|
'Venus': 330.0,
|
|
'Saturn': 300.0,
|
|
}
|
|
|
|
result = calc_tajika_strength_layers(planet_lons, asc_lon=15.0, year_lord='Jupiter')
|
|
|
|
assert result['status'] == 'partial'
|
|
assert result['method'] == 'Tajika Harsha/Panchavargiya Bala'
|
|
assert 'Panchavargiya Bala' in result['blocked_layers']
|
|
assert result['usable_layers'] == ['Harsha Bala']
|
|
assert result['summary']['next_action']
|
|
|
|
for planet in ('Sun', 'Moon', 'Mars', 'Mercury', 'Jupiter', 'Venus', 'Saturn'):
|
|
assert planet in result['harsha_bala']
|
|
assert result['harsha_bala'][planet]['status'] == 'usable'
|
|
assert planet in result['panchavargiya_bala']
|
|
assert result['panchavargiya_bala'][planet]['status'] == 'blocked'
|
|
assert result['combined_strength'][planet]['status'] == 'blocked'
|
|
assert result['combined_strength'][planet]['max_score'] > 0
|
|
|
|
|
|
# ── Tajika Yogas Tests ─────────────────────────────────────────────
|
|
|
|
class TestTajikaYogas:
|
|
def test_legacy_adapter_blocks_without_speeds(self):
|
|
# Moon(15.0) and Mercury(14.5) in same sign, close degrees
|
|
planet_lons = {'Moon': 15.0, 'Mercury': 14.5, 'Sun': 45.0,
|
|
'Mars': 90.0, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
|
|
result = calc_tajika_yogas(planet_lons)
|
|
assert result['status'] == 'blocked'
|
|
assert result['ithasala'] == []
|
|
assert len(result['ithasala']) >= 0 # May or may not detect based on rules
|
|
|
|
def test_graha_yuddha_is_not_inferred_by_legacy_adapter(self):
|
|
# Mercury and Venus very close
|
|
planet_lons = {'Sun': 45.0, 'Moon': 120.0, 'Mars': 90.0,
|
|
'Mercury': 100.0, 'Venus': 100.5, 'Jupiter': 180.0, 'Saturn': 300.0}
|
|
result = calc_tajika_yogas(planet_lons)
|
|
assert result['graha_yuddha'] == []
|
|
|
|
def test_nakta_is_not_inferred_from_sun_moon_co_sign(self):
|
|
planet_lons = {'Sun': 15.0, 'Moon': 18.0, 'Mars': 90.0,
|
|
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
|
|
result = calc_tajika_yogas(planet_lons)
|
|
assert result['nakta'] == []
|
|
|
|
def test_summary_present(self):
|
|
planet_lons = {'Sun': 45.0, 'Moon': 120.0, 'Mars': 90.0,
|
|
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
|
|
result = calc_tajika_yogas(planet_lons)
|
|
assert 'summary' in result
|
|
assert 'Blocked' in result['summary']
|
|
|
|
|
|
class TestDetectTajikaYogas:
|
|
def test_legacy_detector_is_not_a_golden_case_oracle(self):
|
|
# Use close-degree planets to force Ithasala detection
|
|
planets = {'Sun': 14.0, 'Moon': 15.0, 'Mars': 90.0,
|
|
'Mercury': 14.8, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
|
|
yogas = detect_tajika_yogas(planets)
|
|
types = set(y['type'] for y in yogas)
|
|
assert isinstance(yogas, list)
|
|
|
|
def test_legacy_detector_does_not_prove_itasala(self):
|
|
# Moon(15) fast, Sun(14) slow → same sign, close
|
|
planets = {'Sun': 14.0, 'Moon': 15.0, 'Mars': 90.0,
|
|
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
|
|
yogas = detect_tajika_yogas(planets)
|
|
types = set(y['type'] for y in yogas)
|
|
assert isinstance(types, set)
|
|
|
|
def test_kuta_yoga_three_planets_same_sign(self):
|
|
planets = {'Sun': 5.0, 'Moon': 8.0, 'Mars': 12.0,
|
|
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
|
|
yogas = detect_tajika_yogas(planets)
|
|
types = set(y['type'] for y in yogas)
|
|
assert 'Kuta' in types
|
|
|
|
|
|
# ── Vedha Detection Tests ──────────────────────────────────────────
|
|
|
|
class TestVedhaDetection:
|
|
def test_vedha_returns_list(self):
|
|
planets = {'Sun': 45.0, 'Moon': 120.0, 'Mars': 90.0,
|
|
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
|
|
result = detect_vedha(planets)
|
|
assert isinstance(result, list)
|
|
|
|
def test_vedha_structure(self):
|
|
planets = {'Sun': 45.0, 'Moon': 120.0, 'Mars': 90.0,
|
|
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0, 'Saturn': 300.0}
|
|
result = detect_vedha(planets)
|
|
if result:
|
|
assert 'planets' in result[0]
|
|
assert 'description' in result[0]
|
|
|
|
|
|
# ── Sahams Tests ────────────────────────────────────────────────────
|
|
|
|
class TestSahams:
|
|
def test_sahams_block_without_location_context(self):
|
|
result = calc_all_sahams({'Sun': 45.0, 'Moon': 120.0}, 10.0, datetime(1990, 6, 15, 12, 0))
|
|
assert result['status'] == 'blocked'
|
|
|
|
def test_tajika_module_exposes_saham_rules_reference_path(self):
|
|
assert SAHAM_RULES_PATH.endswith('references/saham_rules.json')
|
|
assert os.path.exists(SAHAM_RULES_PATH)
|
|
|
|
def test_all_sahams_calculated(self):
|
|
planet_lons = {'Sun': 45.0, 'Moon': 120.0, 'Mars': 90.0,
|
|
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0,
|
|
'Saturn': 300.0, 'Rahu': 150.0, 'Ketu': 330.0}
|
|
asc_lon = 10.0
|
|
birth_dt = datetime(1990, 6, 15, 10, 30)
|
|
result = calc_all_sahams(planet_lons, asc_lon, birth_dt, lat=39.9042, lon=116.4074, tz=8)
|
|
assert 'punya_saham' in result
|
|
assert 'karya_saham' in result
|
|
assert 'vivah_saham' in result
|
|
|
|
def test_saham_longitude_in_range(self):
|
|
planet_lons = {'Sun': 45.0, 'Moon': 120.0, 'Mars': 90.0,
|
|
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0,
|
|
'Saturn': 300.0, 'Rahu': 150.0, 'Ketu': 330.0}
|
|
result = calc_all_sahams(planet_lons, 10.0, datetime(1990, 6, 15, 10, 30))
|
|
for key, val in result.items():
|
|
if isinstance(val, dict) and 'longitude' in val:
|
|
assert 0 <= val['longitude'] < 360
|
|
|
|
def test_punya_saham_formula(self):
|
|
# Punya = Asc + (Moon - Sun), sourced from references/saham_rules.json
|
|
sun, moon, asc = 45.0, 120.0, 10.0
|
|
expected = (asc + (moon - sun)) % 360 # = 10 + 75 = 85
|
|
planet_lons = {'Sun': sun, 'Moon': moon, 'Mars': 90.0,
|
|
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0,
|
|
'Saturn': 300.0, 'Rahu': 150.0, 'Ketu': 330.0}
|
|
result = calc_all_sahams(planet_lons, asc, datetime(1990, 6, 15, 12, 0), lat=39.9042, lon=116.4074, tz=8)
|
|
assert abs(result['punya_saham']['longitude'] - expected) < 0.01
|
|
|
|
def test_karma_saham_uses_reference_json_day_formula(self):
|
|
# Karma_Saham day rule = Mars - Mercury + Asc, sourced from references/saham_rules.json
|
|
asc = 10.0
|
|
planet_lons = {'Sun': 45.0, 'Moon': 120.0, 'Mars': 90.0,
|
|
'Mercury': 60.0, 'Jupiter': 180.0, 'Venus': 210.0,
|
|
'Saturn': 300.0, 'Rahu': 150.0, 'Ketu': 330.0}
|
|
expected = (asc + (90.0 - 60.0)) % 360
|
|
result = calc_all_sahams(planet_lons, asc, datetime(1990, 6, 15, 12, 0), lat=39.9042, lon=116.4074, tz=8)
|
|
assert abs(result['karma_saham']['longitude'] - expected) < 0.01
|
|
|
|
def test_formula_saham_applies_reference_add_30_exception(self):
|
|
from tajika import _calc_formula_saham
|
|
|
|
# Asc 50 is outside the forward 100 -> 200 zodiacal arc.
|
|
result = _calc_formula_saham(
|
|
'Punya_Saham',
|
|
{'Sun': 200.0, 'Moon': 100.0},
|
|
50.0,
|
|
True,
|
|
{},
|
|
)
|
|
assert result == 340.0
|
|
|
|
def test_is_faster_moon_vs_sun(self):
|
|
assert _is_faster('Moon', 'Sun')
|
|
assert _is_faster('Mercury', 'Jupiter')
|