Files
Jyotisha/tests/test_jaimini.py
T
2026-07-16 23:45:00 +08:00

269 lines
10 KiB
Python

#!/usr/bin/env python3
"""Tests for jaimini.py — Chara Karaka, Arudha Pada, Karakamsha, Special Lagnas."""
from __future__ import annotations
import sys, os, pytest
SCRIPTS = os.path.join(os.path.dirname(__file__), '..', 'scripts')
if SCRIPTS not in sys.path:
sys.path.insert(0, SCRIPTS)
from jaimini import (
calc_chara_karaka_7, calc_chara_karaka_8,
calc_arudha_pada_for_house, calc_arudha_padas, calc_upapada,
calc_graha_padas, calc_karakamsha, calc_special_lagnas, calc_special_lagnas_precise,
calc_chara_dasha, calc_chara_dasha_with_antardasha,
KARAKA_7, KARAKA_8, SIGNS, SIGN_LORDS,
)
# Sample planet degrees (degrees within sign, 0-30)
SAMPLE_DEGREES = {
'Sun': 25.5, 'Moon': 12.3, 'Mars': 8.7,
'Mercury': 20.1, 'Jupiter': 15.0, 'Venus': 3.5, 'Saturn': 28.9
}
# Sample planet longitudes (0-360)
SAMPLE_LONGS = {
'Sun': 25.5, 'Moon': 42.3, 'Mars': 68.7,
'Mercury': 80.1, 'Jupiter': 105.0, 'Venus': 153.5,
'Saturn': 298.9, 'Rahu': 180.0, 'Ketu': 0.0,
}
# ── Chara Karaka 7 Tests ───────────────────────────────────────────
class TestCharaKaraka7:
def test_highest_degree_is_ak(self):
result = calc_chara_karaka_7(SAMPLE_DEGREES)
ak = result['karaka_table']['Atmakaraka']
assert ak['planet'] == 'Saturn' # 28.9 is highest
def test_lowest_degree_is_dk(self):
result = calc_chara_karaka_7(SAMPLE_DEGREES)
dk = result['karaka_table']['Darakaraka']
assert dk['planet'] == 'Venus' # 3.5 is lowest
def test_7_karakas_assigned(self):
result = calc_chara_karaka_7(SAMPLE_DEGREES)
assert len(result['karaka_table']) == 7
def test_karaka_names_correct(self):
result = calc_chara_karaka_7(SAMPLE_DEGREES)
expected = set(KARAKA_7.values())
actual = set(result['karaka_table'].keys())
assert actual == expected
def test_rahu_excluded(self):
degrees = {'Sun': 10.0, 'Moon': 20.0, 'Mars': 5.0,
'Mercury': 15.0, 'Jupiter': 25.0, 'Venus': 8.0,
'Saturn': 12.0, 'Rahu': 29.0}
result = calc_chara_karaka_7(degrees)
planets = [v['planet'] for v in result['karaka_table'].values()]
assert 'Rahu' not in planets
def test_summary_present(self):
result = calc_chara_karaka_7(SAMPLE_DEGREES)
assert 'summary' in result
assert 'AK' in result['summary']
# ── Chara Karaka 8 Tests ───────────────────────────────────────────
class TestCharaKaraka8:
def test_8_karakas_assigned(self):
degrees = dict(SAMPLE_DEGREES)
degrees['Rahu'] = 22.0
result = calc_chara_karaka_8(degrees)
assert len(result['karaka_table_8']) == 8
def test_pitrukaraka_present(self):
degrees = dict(SAMPLE_DEGREES)
degrees['Rahu'] = 22.0
result = calc_chara_karaka_8(degrees)
assert 'Pitrukaraka' in result['karaka_table_8']
def test_ketu_excluded(self):
degrees = dict(SAMPLE_DEGREES)
degrees['Ketu'] = 27.0
result = calc_chara_karaka_8(degrees)
planets = [v['planet'] for v in result['karaka_table_8'].values()]
assert 'Ketu' not in planets
# ── Arudha Pada Tests ──────────────────────────────────────────────
class TestArudhaPada:
def test_arudha_lagna_a1(self):
result = calc_arudha_padas(0, SAMPLE_LONGS) # Aries asc
assert 'A1' in result['padas']
assert 'sign' in result['padas']['A1']
def test_upapada_ul(self):
result = calc_arudha_padas(0, SAMPLE_LONGS)
assert 'UL' in result['padas']
def test_all_12_padas(self):
result = calc_arudha_padas(0, SAMPLE_LONGS)
assert len(result['padas']) == 12
def test_exception_triggered(self):
# If pada falls back in same sign or 7th, exception applies
# This depends on planet positions
result = calc_arudha_padas(0, SAMPLE_LONGS)
for pada in result['padas'].values():
assert 'exception_triggered' in pada
def test_upapada_standalone(self):
result = calc_upapada(0, SAMPLE_LONGS)
if result:
assert 'sign' in result
assert 'second_from_ul' in result
# ── Karakamsha Tests ───────────────────────────────────────────────
class TestKarakamsha:
def test_karakamsha_sign(self):
result = calc_karakamsha('Leo', 15.0)
assert result['karakamsha_sign'] == 'Leo'
assert result['karakamsha_lord'] == 'Sun'
def test_soul_direction(self):
result = calc_karakamsha('Cancer', 10.0)
assert 'soul_direction' in result
assert 'sign_direction' in result['soul_direction']
assert 'lord_method' in result['soul_direction']
@pytest.mark.parametrize("sign,expected_lord",
[('Aries', 'Mars'), ('Taurus', 'Venus'), ('Gemini', 'Mercury'),
('Cancer', 'Moon'), ('Leo', 'Sun'), ('Virgo', 'Mercury')])
def test_karakamsha_lord(self, sign, expected_lord):
result = calc_karakamsha(sign, 10.0)
assert result['karakamsha_lord'] == expected_lord
# ── Special Lagnas Tests ───────────────────────────────────────────
class TestSpecialLagnas:
def test_hl_gl_vl_present(self):
result = calc_special_lagnas(0, 10, 30) # Aries asc, 10:30
assert 'HL' in result
assert 'GL' in result
assert 'VL' in result
assert 'PP' in result
assert 'ViL' in result
def test_ghatis_calculated(self):
result = calc_special_lagnas(0, 10, 30)
assert 'ghatis_elapsed_from_midnight' in result
assert result['ghatis_elapsed_from_midnight'] > 0
def test_vl_based_on_asc(self):
result = calc_special_lagnas(5, 10, 0) # Virgo asc
assert result['VL']['sign_idx'] == (5 * 3) % 12
def test_each_sign_has_lord(self):
result = calc_special_lagnas(0, 10, 30)
for key in ['HL', 'GL', 'VL']:
assert result[key]['lord'] in SIGN_LORDS.values()
def test_note_about_sunrise(self):
result = calc_special_lagnas(0, 10, 30)
assert 'note' in result
def test_precise_special_lagnas_use_sunrise_reference(self):
result = calc_special_lagnas_precise(
0, 1990, 6, 15, 10, 30, lat=28.6, lon=77.2, tz_offset=5.5
)
assert result['capability_status'] == 'covered'
assert result['precision'] == 'sunrise_correct'
assert 'sunrise_local_time' in result
assert result['ghatis_elapsed_from_sunrise'] > 0
for key in ['HL', 'GL', 'VL', 'PP', 'ViL']:
assert result[key]['sign'] in SIGNS
assert result[key]['lord'] in SIGN_LORDS.values()
def test_precise_special_lagnas_include_varnada_crosscheck(self):
result = calc_special_lagnas_precise(
4, 1990, 4, 17, 14, 45, lat=36.466667, lon=114.2, tz_offset=8
)
assert result['VL']['sign_idx'] == (4 * 3) % 12
assert 'vl_from_hl' in result['VL']
def test_precise_special_lagnas_expose_named_extended_payloads(self):
result = calc_special_lagnas_precise(
0, 1990, 6, 15, 10, 30, lat=28.6, lon=77.2, tz_offset=5.5
)
assert result['PP']['full_name'] == 'Pranapada Lagna'
assert result['ViL']['full_name'] == 'Vighati Lagna'
def test_precise_special_lagnas_are_time_sensitive(self):
morning = calc_special_lagnas_precise(
0, 1990, 6, 15, 10, 0, lat=28.6, lon=77.2, tz_offset=5.5
)
later = calc_special_lagnas_precise(
0, 1990, 6, 15, 11, 0, lat=28.6, lon=77.2, tz_offset=5.5
)
assert later['ghatis_elapsed_from_sunrise'] > morning['ghatis_elapsed_from_sunrise']
def test_precise_special_lagnas_preserve_fractional_minutes(self):
minute_only = calc_special_lagnas_precise(
4, 1990, 4, 17, 14, 45, lat=36.466667, lon=114.2, tz_offset=8
)
with_seconds = calc_special_lagnas_precise(
4, 1990, 4, 17, 14, 45 + 20 / 60.0, lat=36.466667, lon=114.2, tz_offset=8
)
assert with_seconds['birth_utc_hours'] > minute_only['birth_utc_hours']
assert with_seconds['ghatis_elapsed_from_sunrise'] > minute_only['ghatis_elapsed_from_sunrise']
# ── Graha Padas Tests ──────────────────────────────────────────────
class TestGrahaPadas:
def test_graha_padas_calculated(self):
result = calc_graha_padas(SAMPLE_LONGS)
assert 'graha_padas' in result
assert len(result['graha_padas']) > 0
def test_rahu_ketu_excluded(self):
result = calc_graha_padas(SAMPLE_LONGS)
assert 'Rahu' not in result['graha_padas']
assert 'Ketu' not in result['graha_padas']
def test_graha_pada_structure(self):
result = calc_graha_padas(SAMPLE_LONGS)
for pname, pada in result['graha_padas'].items():
assert 'graha_pada_sign' in pada
assert 'lord' in pada
# ── Chara Dasha Tests ──────────────────────────────────────────────
class TestCharaDasha:
def test_12_signs_in_sequence(self):
result = calc_chara_dasha(0, SAMPLE_LONGS, 1990, 6)
assert len(result['dasha_sequence']) == 12
def test_total_cycle_years(self):
result = calc_chara_dasha(0, SAMPLE_LONGS, 1990, 6)
assert result['total_cycle_years'] > 0
def test_ascendant_correct(self):
result = calc_chara_dasha(0, SAMPLE_LONGS, 1990, 6)
assert result['ascendant'] == 'Aries'
def test_dignity_adjustment_present(self):
result = calc_chara_dasha(0, SAMPLE_LONGS, 1990, 6)
for d in result['dasha_sequence']:
assert 'dignity_adjustment' in d
def test_antardasha_calculated(self):
result = calc_chara_dasha_with_antardasha(0, SAMPLE_LONGS, 1990, 6)
assert result['has_antardasha'] == True
for md in result['dasha_sequence']:
assert len(md['antardashas']) > 0
def test_pratyantar_calculated(self):
result = calc_chara_dasha_with_antardasha(0, SAMPLE_LONGS, 1990, 6)
assert result['has_pratyantar'] == True