729 lines
26 KiB
Python
729 lines
26 KiB
Python
#!/usr/bin/env python3
|
|
"""印度占星Skill自动化测试运行器 v1.0"""
|
|
import sys, os, time
|
|
from datetime import datetime
|
|
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..'))
|
|
sys.path.insert(0, PROJECT_ROOT)
|
|
sys.path.insert(0, os.path.join(PROJECT_ROOT, 'scripts'))
|
|
|
|
TESTS = []
|
|
|
|
def test(name):
|
|
def decorator(fn): TESTS.append((name, fn)); return fn
|
|
return decorator
|
|
|
|
# === 模块导入测试 ===
|
|
@test("ashtakavarga import")
|
|
def t1(): from ashtakavarga import calc_ashtakavarga, calc_prastara_av, calc_sodhita_av
|
|
|
|
@test("shadbala import")
|
|
def t2(): from shadbala import calc_shadbala
|
|
|
|
@test("jaimini import")
|
|
def t3(): from jaimini import _chara_dasha_duration_knrao, _resolve_chara_dasha_lord
|
|
|
|
@test("bhava_bala import")
|
|
def t4(): from bhava_bala import calc_bhava_bala
|
|
|
|
@test("kakshya import")
|
|
def t5(): from kakshya import calc_kakshya_scores, get_kakshya_lord
|
|
|
|
@test("kp_system import")
|
|
def t6(): from kp_system import get_kp_lords, calc_kp_analysis
|
|
|
|
@test("synastry import")
|
|
def t7(): from synastry import calc_ashtakoot
|
|
|
|
@test("prashna import")
|
|
def t8(): from prashna import calc_prashna_chart, get_kp_prashna_answer
|
|
|
|
@test("remedies import")
|
|
def t9(): from remedies import recommend_remedies, quick_remedy
|
|
|
|
@test("pancha_mahapurusha import")
|
|
def t10(): from pancha_mahapurusha import detect_pancha_mahapurusha
|
|
|
|
@test("sade_sati import")
|
|
def t11(): from sade_sati import calc_sade_sati_complete
|
|
|
|
@test("sudarshana_chakra import")
|
|
def t12(): from sudarshana_chakra import calc_sudarshana_chakra
|
|
|
|
@test("career_analysis import")
|
|
def t13(): from career_analysis import analyze_career
|
|
|
|
@test("relationship_analysis import")
|
|
def t14(): from relationship_analysis import analyze_relationship
|
|
|
|
@test("muhurtha_election import")
|
|
def t15(): from muhurtha_election import evaluate_muhurtha
|
|
|
|
@test("yoga_expansion import")
|
|
def t16(): from yoga_expansion import detect_all_yogas
|
|
|
|
@test("birth_time_rectifier import")
|
|
def t17(): from birth_time_rectifier import check_lagna_boundary, get_effective_accuracy
|
|
|
|
@test("conditional_dashas import")
|
|
def t18(): from conditional_dashas import calc_dwisaptati_dasha, check_dwisaptati_condition
|
|
|
|
@test("extended_dashas import")
|
|
def t19(): from extended_dashas import get_available_dashas, DASHA_REGISTRY
|
|
|
|
@test("chart_renderer import")
|
|
def t20(): from chart_renderer import render_south_indian_chart, render_html_report
|
|
|
|
# === 功能测试 ===
|
|
@test("PAV validation")
|
|
def t21():
|
|
from ashtakavarga import calc_prastara_av, SEVEN_PLANETS
|
|
planets = {p: {'sign': 'Aries', 'degree': i*40} for i,p in enumerate(SEVEN_PLANETS)}
|
|
pav = calc_prastara_av(planets, 0)
|
|
assert pav['all_valid'], "PAV validation failed"
|
|
|
|
@test("Shadbala invariant")
|
|
def t22():
|
|
from shadbala import calc_shadbala
|
|
p = {pn: {'sign': 'Aries', 'degree': i*40, 'house': i+1} for i,pn in enumerate(['Sun','Moon','Mars','Mercury','Jupiter','Venus','Saturn'])}
|
|
result = calc_shadbala(p, 'Aries', 12, 15, 45, 0)
|
|
assert len(result['planets']) == 7
|
|
|
|
@test("KP sublord")
|
|
def t23():
|
|
from kp_system import get_kp_lords
|
|
r = get_kp_lords(15.5)
|
|
assert r['sub_lord'] and r['sub_sub_lord']
|
|
|
|
@test("Synastry score range")
|
|
def t24():
|
|
from synastry import calc_ashtakoot
|
|
r = calc_ashtakoot(15.5, 120)
|
|
assert 0 <= r['total_score'] <= 36
|
|
|
|
@test("Sade Sati detection")
|
|
def t25():
|
|
from sade_sati import calc_sade_sati
|
|
r = calc_sade_sati("Aries", "Aries", datetime.now())
|
|
assert r.get("active") == True
|
|
assert r['active'] and r['phase'] == 'peak'
|
|
|
|
@test("Remedies generation")
|
|
def t26():
|
|
from remedies import recommend_remedies
|
|
sb = {'Sun': {'total_rupas': 0.4}, 'Saturn': {'total_rupas': 0.3}}
|
|
r = recommend_remedies(sb, doshas=['Mangal Dosha'])
|
|
assert len(r['recommendations']['gems']) >= 1
|
|
|
|
@test("Muhurtha evaluation")
|
|
def t27():
|
|
from muhurtha_election import evaluate_muhurtha
|
|
r = evaluate_muhurtha('marriage', 3, 'Rohini', 4, 'Monday', 'Taurus')
|
|
assert r['verdict'] in ('大吉', '尚可', '中性', '不吉')
|
|
|
|
@test("Dasha count")
|
|
def t28():
|
|
from extended_dashas import get_available_dashas
|
|
assert len(get_available_dashas()) >= 30, "Dasha count should be >= 30"
|
|
|
|
@test("Rectifier boundary check")
|
|
def t29():
|
|
from birth_time_rectifier import check_lagna_boundary
|
|
is_b, _ = check_lagna_boundary(1.5)
|
|
assert is_b
|
|
|
|
@test("PMC detection")
|
|
def t30():
|
|
from pancha_mahapurusha import detect_pancha_mahapurusha
|
|
p = {'Mars': {'sign': 'Capricorn', 'house': 4, 'degree': 280}}
|
|
r = detect_pancha_mahapurusha(p)
|
|
assert len(r) >= 1
|
|
|
|
# === v6.7.5 新增功能测试 ===
|
|
@test("PMC combustion cancellation")
|
|
def t31():
|
|
from pancha_mahapurusha import detect_pancha_mahapurusha
|
|
p = {'Mars': {'sign': 'Capricorn', 'house': 4, 'degree': 50}}
|
|
r = detect_pancha_mahapurusha(p, sun_degree=53)
|
|
assert r[0]['is_valid'] == False, "Mars too close to Sun should cancel PMC"
|
|
|
|
@test("PMC retrograde cancellation")
|
|
def t32():
|
|
from pancha_mahapurusha import detect_pancha_mahapurusha
|
|
p = {'Jupiter': {'sign': 'Cancer', 'house': 1, 'degree': 95, 'retrograde': True}}
|
|
r = detect_pancha_mahapurusha(p)
|
|
assert r[0]['is_valid'] == False
|
|
|
|
@test("Bhava Bala computation")
|
|
def t33():
|
|
from bhava_bala import calc_bhava_adhipathi_bala, calc_bhava_dig_bala
|
|
adhi = calc_bhava_adhipathi_bala(['Aries']*12, {'Mars': 500})
|
|
assert len(adhi) == 12
|
|
dig = calc_bhava_dig_bala(['Aries']*12, [15]*12)
|
|
assert len(dig) == 12
|
|
|
|
@test("Kakshya scoring")
|
|
def t34():
|
|
from kakshya import calc_kakshya_scores
|
|
p = {'Sun': {'sign': 'Aries', 'degree': 15.5}}
|
|
r = calc_kakshya_scores(p, 0)
|
|
assert 'Sun' in r['planets']
|
|
|
|
@test("Sudarshana convergence")
|
|
def t35():
|
|
from sudarshana_chakra import calc_sudarshana_chakra
|
|
p = {'Sun': 15.0, 'Moon': 112.0, 'Mars': 280.0}
|
|
r = calc_sudarshana_chakra(p, asc_lon=0.0)
|
|
assert 'convergence' in r
|
|
|
|
@test("Career analysis fields")
|
|
def t36():
|
|
from career_analysis import analyze_career
|
|
p = {'Sun': {'house': 10}, 'Saturn': {'house': 6}}
|
|
r = analyze_career(p, 'Aries')
|
|
assert len(r['fields']) >= 1
|
|
|
|
@test("Relationship Venus check")
|
|
def t37():
|
|
from relationship_analysis import analyze_relationship
|
|
p = {'Venus': {'sign': 'Taurus', 'house': 7}, 'Moon': {'house': 4}}
|
|
r = analyze_relationship(p, 'Aries')
|
|
assert 'assessment' in r
|
|
|
|
@test("Prashna chart creation")
|
|
def t38():
|
|
from prashna import calc_prashna_chart, get_kp_prashna_answer
|
|
from datetime import datetime
|
|
r = calc_prashna_chart(datetime.now(), {'Sun': {'sign': 'Aries'}}, 45.5)
|
|
assert r['asc_sign'] in ['Aries','Taurus','Gemini','Cancer','Leo','Virgo','Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
|
|
|
@test("Prashna KP answer")
|
|
def t39():
|
|
from prashna import get_kp_prashna_answer
|
|
r = get_kp_prashna_answer({'Mars': {'sign': 'Aries'}}, 'career', 15.5)
|
|
assert r['confidence'] in ('高', '中')
|
|
|
|
@test("Prashna Arudha")
|
|
def t40():
|
|
from prashna import detect_prashna_arudha
|
|
r = detect_prashna_arudha({'Mars': {'sign': 'Aries'}}, 15.5, 7)
|
|
assert r['arudha_house'] >= 1
|
|
|
|
@test("Conditional Dasha trigger")
|
|
def t41():
|
|
from conditional_dashas import check_dwisaptati_condition
|
|
assert check_dwisaptati_condition('Sun', 1) == True
|
|
|
|
@test("Conditional Dasha calc")
|
|
def t42():
|
|
from conditional_dashas import calc_dwisaptati_dasha
|
|
from datetime import datetime
|
|
r = calc_dwisaptati_dasha(datetime(1990,6,15), 'Sun', 15.5)
|
|
assert len(r) == 8
|
|
|
|
@test("Extended Dasha registry")
|
|
def t43():
|
|
from extended_dashas import get_dasha_info, get_available_dashas
|
|
assert get_dasha_info('kalachakra')['type'] == 'nakshatra'
|
|
assert len(get_available_dashas()) >= 35
|
|
|
|
@test("Yoga expansion detect")
|
|
def t44():
|
|
from yoga_expansion import detect_kemadruma, detect_graha_yuddha
|
|
r = detect_kemadruma({'Moon': {'sign': 'Aries'}})
|
|
assert isinstance(r, dict)
|
|
|
|
@test("Yoga graha_yuddha")
|
|
def t45():
|
|
from yoga_expansion import detect_graha_yuddha
|
|
r = detect_graha_yuddha({'Mars': {'degree': 50.0}, 'Jupiter': {'degree': 50.3}})
|
|
assert len(r) >= 1
|
|
|
|
@test("Yoga gandanta")
|
|
def t46():
|
|
from yoga_expansion import detect_gandanta
|
|
r = detect_gandanta({'Moon': {'degree': 118.5}}) # Cancer end
|
|
assert len(r) >= 0 # may or may not be gandanta
|
|
|
|
@test("Rectifier accuracy matrix")
|
|
def t47():
|
|
from birth_time_rectifier import get_effective_accuracy, get_enabled_vargas
|
|
acc = get_effective_accuracy('minute', 'hospital')
|
|
assert acc == 'minute'
|
|
v = get_enabled_vargas('minute')
|
|
assert v['D9'] == 'enabled'
|
|
|
|
@test("Tajika Yogas detect")
|
|
def t48():
|
|
from tajika import detect_tajika_yogas
|
|
r = detect_tajika_yogas({'Sun': {'sign': 'Aries', 'degree': 15}, 'Moon': {'sign': 'Aries', 'degree': 18}})
|
|
assert len(r) >= 1
|
|
|
|
@test("Tajika Sahams count")
|
|
def t49():
|
|
from tajika import calc_all_sahams
|
|
from datetime import datetime
|
|
r = calc_all_sahams({'Sun': 80, 'Moon': 105, 'Mars': 220, 'Mercury': 75, 'Jupiter': 310, 'Venus': 350, 'Saturn': 180, 'Rahu': 45, 'Ketu': 225}, 15.0, datetime(1990,6,15,12,0), lat=39.9042, lon=116.4074, tz=8)
|
|
assert len(r) >= 30
|
|
|
|
@test("Chart renderer SVG")
|
|
def t50():
|
|
from chart_renderer import render_south_indian_chart
|
|
svg = render_south_indian_chart({'Sun': 'Aries', 'Moon': 'Cancer'}, 'Aries')
|
|
assert '<svg' in svg and '</svg>' in svg
|
|
|
|
# ========================================================================
|
|
# v6.9.14: 扩展测试 — 50→475+ 覆盖核心计算模块
|
|
# ========================================================================
|
|
|
|
# ── Shadbala precision tests ──
|
|
@test("Shadbala digs to 2 decimal places")
|
|
def t51():
|
|
from shadbala import calc_shadbala
|
|
s = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo','Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
|
p = {}
|
|
for i,(pn,d) in enumerate([('Sun',15),('Moon',75),('Mars',220),('Mercury',55),('Jupiter',310),('Venus',350),('Saturn',180)]):
|
|
p[pn] = {'sign':s[int(d/30)%12],'degree':d,'house':i+1}
|
|
r = calc_shadbala(p, 'Aries', 12, 15, 75, 0)
|
|
for pn, d in r['planets'].items():
|
|
assert isinstance(d['total_rupas'], float), f"{pn} total_rupas should be float"
|
|
assert 0 < d['total_rupas'] < 20, f"{pn} rupas out of range"
|
|
|
|
@test("Shadbala absolute component invariant")
|
|
def t52():
|
|
from shadbala import calc_shadbala
|
|
s = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo','Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
|
p = {}
|
|
for i,(pn,d) in enumerate([('Sun',15),('Moon',75),('Mars',220),('Mercury',55),('Jupiter',310),('Venus',350),('Saturn',180)]):
|
|
p[pn] = {'sign':s[int(d/30)%12],'degree':d,'house':i+1}
|
|
r = calc_shadbala(p, 'Aries', 12, 15, 75, 0)
|
|
for pn, d in r['planets'].items():
|
|
component_sum = (
|
|
d['sthana_bala']['total'] + d['dig_bala'] + d['kala_bala']['total'] +
|
|
d['chesta_bala'] + d['naisargika_bala'] + d['drik_bala']
|
|
)
|
|
assert abs(d['total_virupas'] - component_sum) < 0.1, f"{pn} total should equal component sum"
|
|
|
|
# ── Yoga engine deep tests ──
|
|
@test("Yoga engine Raja detection")
|
|
def t53():
|
|
from yoga_engine import YogaEngine
|
|
engine = YogaEngine('references/yoga_rules.json')
|
|
p = {pn: {'sign': s, 'house': h, 'degree': 15} for pn, s, h in [
|
|
('Sun','Leo',5),('Moon','Cancer',4),('Mars','Scorpio',8),
|
|
('Mercury','Gemini',3),('Jupiter','Scorpio',8),('Venus','Libra',7),
|
|
('Saturn','Capricorn',10),
|
|
]}
|
|
r = engine.detect(p, 'Scorpio')
|
|
assert len(r) >= 1, "Should detect at least 1 yoga"
|
|
|
|
@test("Yoga engine rules loaded")
|
|
def t54():
|
|
from yoga_engine import YogaEngine
|
|
engine = YogaEngine('references/yoga_rules.json')
|
|
assert len(engine.rules) >= 400, f"Should have 400+ rules, got {len(engine.rules)}"
|
|
|
|
@test("Yoga engine solar lunar detection")
|
|
def t55():
|
|
from yoga_engine import YogaEngine
|
|
engine = YogaEngine('references/yoga_rules.json')
|
|
p = {pn: {'sign': s, 'house': h, 'degree': 15} for pn, s, h in [
|
|
('Sun','Aries',1),('Moon','Pisces',12),('Mars','Taurus',2),
|
|
('Mercury','Gemini',3),('Jupiter','Sagittarius',9),
|
|
('Venus','Aquarius',11),('Saturn','Capricorn',10),
|
|
]}
|
|
r = engine.detect(p, 'Aries')
|
|
names = [str(y) for y in r]
|
|
assert any("solar" in str(y).lower() or "Veshi" in str(y) or "Yoga" in str(y) for y in r), f"Got {len(r)} yogas"
|
|
|
|
# ── Ashtakavarga extended tests ──
|
|
@test("PAV validation all valid")
|
|
def t56():
|
|
from ashtakavarga import calc_prastara_av
|
|
s = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo','Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
|
p = {}
|
|
for i,(pn,d) in enumerate([('Sun',15),('Moon',75),('Mars',220),('Mercury',55),('Jupiter',310),('Venus',350),('Saturn',180)]):
|
|
p[pn] = {'sign':s[int(d/30)%12],'degree':d}
|
|
r = calc_prastara_av(p, 0)
|
|
assert r['all_valid'] == True
|
|
|
|
@test("Sodhita less or equal to original")
|
|
def t57():
|
|
from ashtakavarga import calc_ashtakavarga, calc_sodhita_av
|
|
s = ['Aries','Taurus','Gemini','Cancer','Leo','Virgo','Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
|
p = {}
|
|
for i,(pn,d) in enumerate([('Sun',15),('Moon',75),('Mars',220),('Mercury',55),('Jupiter',310),('Venus',350),('Saturn',180)]):
|
|
p[pn] = {'sign':s[int(d/30)%12],'degree':d}
|
|
av = calc_ashtakavarga(p, 0)
|
|
sodhita = calc_sodhita_av(av['bav'], p, 0)
|
|
for pn in sodhita['sodhita_bav']:
|
|
for i in range(12):
|
|
assert sodhita['sodhita_bav'][pn][i] <= 8, f"Sodhita {pn}[{i}] should <= 8"
|
|
|
|
# ── Dasha system tests ──
|
|
@test("Vimshottari remaining years positive")
|
|
def t58():
|
|
from dasha_calculator_enhanced import calculate_precise_remaining_years
|
|
r = calculate_precise_remaining_years(75) # Moon at 75°
|
|
assert r['remaining_years'] > 0
|
|
assert r['lord'] in ['Ketu','Venus','Sun','Moon','Mars','Rahu','Jupiter','Saturn','Mercury']
|
|
|
|
@test("Vimshottari sequence 9 MDs")
|
|
def t59():
|
|
from dasha_calculator_enhanced import calculate_dasha_dates
|
|
from datetime import datetime
|
|
r = calculate_dasha_dates(datetime(1990,6,15), 75)
|
|
assert len(r) == 9, f"Should be 9 MD periods, got {len(r)}"
|
|
|
|
@test("Chara Dasha duration within range")
|
|
def t60():
|
|
from jaimini import calc_chara_dasha
|
|
from jaimini import SIGNS
|
|
longs = {'Sun': 15, 'Moon': 75, 'Mars': 220, 'Mercury': 55, 'Jupiter': 310, 'Venus': 350, 'Saturn': 180}
|
|
r = calc_chara_dasha(0, longs, 1990, 6, 15)
|
|
seq = r.get('dasha_sequence', r) if isinstance(r, dict) else r
|
|
durations = [e.get('duration_years', e.get('duration', 0)) for e in seq]
|
|
assert len(seq) >= 8, f"Should have 8+ periods, got {len(seq)}"
|
|
assert all(d > 0 for d in durations), f"All Chara Dasha durations should be positive: {durations}"
|
|
|
|
@test("Yogini Dasha 8 periods")
|
|
def t61():
|
|
from extended_dashas import calc_yogini_dasha
|
|
from datetime import datetime
|
|
r = calc_yogini_dasha(datetime(1990,6,15), 5)
|
|
assert len(r) == 8
|
|
|
|
@test("Kalachakra Dasha")
|
|
def t62():
|
|
from extended_dashas import calc_kalachakra_dasha
|
|
from datetime import datetime
|
|
r = calc_kalachakra_dasha(datetime(1990,6,15), 5, 1)
|
|
assert len(r) >= 8
|
|
|
|
# ── KP system tests ──
|
|
@test("KP sublord calculation")
|
|
def t63():
|
|
from kp_system import get_kp_lords
|
|
r = get_kp_lords(15.5)
|
|
assert r['nakshatra'] is not None
|
|
assert r['sub_lord'] is not None
|
|
|
|
@test("KP subsublord calculation")
|
|
def t64():
|
|
from kp_system import get_kp_lords
|
|
r = get_kp_lords(120.0)
|
|
assert r['sub_sub_lord'] is not None
|
|
|
|
@test("KP analysis returns houses")
|
|
def t65():
|
|
from kp_system import calc_kp_analysis
|
|
planets = {'Sun': {'sign': 'Aries', 'degree': 15.5, 'house': 1}}
|
|
r = calc_kp_analysis(planets, 'Aries')
|
|
assert len(r.get('houses', {})) >= 1
|
|
|
|
# ── Divisional charts tests ──
|
|
@test("D9 position correct for Aries")
|
|
def t66():
|
|
from divisional_charts_extended import DivisionalChartsCalculator
|
|
calc = DivisionalChartsCalculator()
|
|
r = calc._calculate_varga_position(15.0, 9)
|
|
assert 0 <= r < 360
|
|
|
|
@test("D81 nested")
|
|
def t67():
|
|
from divisional_charts_extended import DivisionalChartsCalculator
|
|
calc = DivisionalChartsCalculator()
|
|
r = calc._calculate_varga_position(15.0, 81)
|
|
assert 0 <= r < 360
|
|
|
|
@test("D108 nested")
|
|
def t68():
|
|
from divisional_charts_extended import DivisionalChartsCalculator
|
|
calc = DivisionalChartsCalculator()
|
|
r = calc._calculate_varga_position(15.0, 108)
|
|
assert 0 <= r < 360
|
|
|
|
# ── Synastry tests ──
|
|
@test("Synastry score in 0-36 range")
|
|
def t69():
|
|
from synastry import calc_ashtakoot
|
|
r = calc_ashtakoot(15.5, 120.0)
|
|
assert 0 <= r['total_score'] <= 36
|
|
|
|
@test("Synastry all 8 factors present")
|
|
def t70():
|
|
from synastry import calc_ashtakoot
|
|
r = calc_ashtakoot(15.5, 75.0)
|
|
expected = ['Varna','Vashya','Tara','Yoni','GrahaMaitri','Gana','Bhakoot','Nadi']
|
|
for e in expected:
|
|
assert e in r.get('scores', {}), f"Missing {e}"
|
|
|
|
# ── Divisional yoga tests ──
|
|
@test("Divisional yoga D9 conversion")
|
|
def t71():
|
|
from divisional_yoga import convert_to_varga, detect_varga_yogas
|
|
vp = convert_to_varga({'Sun': 15, 'Moon': 75}, 'D9')
|
|
assert 'Sun' in vp
|
|
assert vp['Sun']['sign'] in ['Aries','Taurus','Gemini','Cancer','Leo','Virgo','Libra','Scorpio','Sagittarius','Capricorn','Aquarius','Pisces']
|
|
|
|
@test("Divisional yoga detection runs")
|
|
def t72():
|
|
from divisional_yoga import detect_varga_yogas
|
|
p = {'Sun': 15, 'Moon': 75, 'Mars': 220}
|
|
r = detect_varga_yogas(p, 'D9')
|
|
assert isinstance(r, list)
|
|
|
|
# ── Transit trigger tests ──
|
|
@test("Transit trigger search produces results")
|
|
def t73():
|
|
from transit_trigger import search_transit_triggers
|
|
from datetime import datetime, timedelta
|
|
r = search_transit_triggers('Saturn', 15.0, datetime(2026,6,1), datetime(2026,12,31))
|
|
assert isinstance(r, list)
|
|
|
|
# ── Varshaphala tests ──
|
|
@test("Varshaphala report structure")
|
|
def t74():
|
|
from varshaphala import varshaphala_report
|
|
natal = {'Sun':{'sign':'Gemini','degree':22},'Moon':{'sign':'Pisces','degree':5}}
|
|
r = varshaphala_report(1990,6,15,12,39.9,116.4,8,natal,'Virgo',2026)
|
|
assert 'solar_return' in r
|
|
assert 'muntha' in r
|
|
assert 'predictions' in r
|
|
|
|
# ── Remedies tests ──
|
|
@test("Remedies weak planet detected")
|
|
def t75():
|
|
from remedies import recommend_remedies
|
|
r = recommend_remedies({'Sun':{'total_rupas':0.4},'Saturn':{'total_rupas':0.3}}, doshas=['Mangal Dosha'])
|
|
assert len(r['recommendations']['gems']) >= 1
|
|
|
|
@test("Remedies dosha coverage")
|
|
def t76():
|
|
from remedies import recommend_remedies
|
|
r = recommend_remedies({'Moon':{'total_rupas':0.6}}, doshas=['Kaal Sarp Dosha','Pitra Dosha'])
|
|
assert len(r['recommendations'].get('dosha_remedies',[])) >= 1
|
|
|
|
# ── Pancha Mahapurusha tests ──
|
|
@test("PMC Hamsa Yoga")
|
|
def t77():
|
|
from pancha_mahapurusha import detect_pancha_mahapurusha
|
|
p = {'Jupiter':{'sign':'Cancer','house':1,'degree':95}}
|
|
r = detect_pancha_mahapurusha(p)
|
|
names = [y.get("name","?") for y in r]
|
|
assert any("Hamsa" in n for n in names), f"Expected Hamsa in {names}"
|
|
|
|
@test("PMC Malavya Yoga")
|
|
def t78():
|
|
from pancha_mahapurusha import detect_pancha_mahapurusha
|
|
p = {'Venus':{'sign':'Pisces','house':7,'degree':345}}
|
|
r = detect_pancha_mahapurusha(p)
|
|
names = [y.get("name","?") for y in r]
|
|
assert any("Malavya" in n for n in names), f"Expected Malavya in {names}"
|
|
|
|
# ── Sade Sati tests ──
|
|
@test("Sade Sati peak detection")
|
|
def t79():
|
|
from sade_sati import calc_sade_sati
|
|
r = calc_sade_sati("Aries", "Aries", datetime.now())
|
|
assert r.get("active") == True
|
|
|
|
@test("Sade Sati inactive")
|
|
def t80():
|
|
from sade_sati import calc_sade_sati
|
|
r = calc_sade_sati('Aries', 'Leo')
|
|
assert r['active'] == False
|
|
|
|
# ── Birth time rectifier tests ──
|
|
@test("Rectifier confidence calculation")
|
|
def t81():
|
|
from birth_time_rectifier import calculate_confidence
|
|
r = calculate_confidence(8, 10, 'minute', False)
|
|
assert 80 <= r['confidence'] <= 100
|
|
|
|
# ── Career / Relationship engine tests ──
|
|
@test("Career analysis returns fields")
|
|
def t82():
|
|
from career_analysis import analyze_career
|
|
p = {'Sun':{'house':10,'sign':'Leo'},'Saturn':{'house':6},'Venus':{'house':7}}
|
|
r = analyze_career(p, 'Aries')
|
|
assert len(r.get('fields',[])) >= 1
|
|
|
|
@test("Career analysis has assessment")
|
|
def t83():
|
|
from career_analysis import analyze_career
|
|
p = {'Sun':{'house':10},'Moon':{'house':4}}
|
|
r = analyze_career(p, 'Aries')
|
|
assert 'assessment' in r
|
|
|
|
# ── Misconceptions tests ──
|
|
@test("Fallacy detected for debilitated Saturn")
|
|
def t84():
|
|
from misconceptions import check_for_fallacies
|
|
interp = {'planets': {'Saturn': {'dignity': 'debilitated', 'note': '土星落陷,事业会坏'}}}
|
|
r = check_for_fallacies(interp)
|
|
assert len(r) >= 1
|
|
|
|
@test("Fallacy detected for Ketu 10th")
|
|
def t85():
|
|
from misconceptions import check_for_fallacies
|
|
interp = {'planets': {'Ketu': {'house': 10, 'note': 'Ketu 10宫=事业毁灭'}}}
|
|
r = check_for_fallacies(interp)
|
|
assert len(r) >= 1
|
|
|
|
# ── Case validator tests ──
|
|
@test("Case validation for Saturn debilitated")
|
|
def t86():
|
|
from case_validator import validate_config
|
|
r = validate_config('Saturn', 'debilitated')
|
|
assert r['validated'] == True
|
|
|
|
# ── Muhurtha tests ──
|
|
@test("Muhurtha marriage evaluation")
|
|
def t87():
|
|
from muhurtha_election import evaluate_muhurtha
|
|
r = evaluate_muhurtha('marriage', 3, 'Rohini', 4, 'Monday', 'Taurus', {
|
|
'Moon': {'sign':'Cancer','house':5},
|
|
'Venus': {'sign':'Taurus','house':2}
|
|
})
|
|
assert 'verdict' in r
|
|
assert 'score' in r
|
|
|
|
@test("Muhurtha bad timing detection")
|
|
def t88():
|
|
from muhurtha_election import evaluate_muhurtha
|
|
r = evaluate_muhurtha('business', 4, 'Bharani', 5, 'Tuesday', 'Aries')
|
|
assert r['score'] < 8
|
|
|
|
# ── Chart renderer tests ──
|
|
@test("Chart renderer SVG has planets")
|
|
def t89():
|
|
from chart_renderer import render_south_indian_chart
|
|
svg = render_south_indian_chart({
|
|
'Sun': 'Aries','Moon': 'Cancer','Mars': 'Scorpio','Mercury': 'Taurus',
|
|
'Jupiter': 'Sagittarius','Venus': 'Libra','Saturn': 'Capricorn',
|
|
'Rahu': 'Pisces','Ketu': 'Virgo',
|
|
}, 'Aries')
|
|
found = [p for p in ["Moon","Mars","Jupiter"] if p in svg]
|
|
assert len(found) >= 2, f"Only found {found} in SVG"
|
|
|
|
# ── Multiple Dasha co-existence tests ──
|
|
@test("Dasha registry entries unique")
|
|
def t90():
|
|
from extended_dashas import DASHA_REGISTRY, DASHA_CALCULATORS
|
|
assert len(DASHA_REGISTRY) == 35
|
|
assert len(DASHA_CALCULATORS) >= 32
|
|
|
|
@test("Generic Dasha produces results")
|
|
def t91():
|
|
from extended_dashas import calc_any_dasha
|
|
from datetime import datetime
|
|
r = calc_any_dasha('shodasottari', datetime(1990,6,15), moon_nak_idx=0)
|
|
assert len(r) >= 8
|
|
|
|
# ── Tajika tests ──
|
|
@test("Tajika detection with close planets")
|
|
def t92():
|
|
from tajika import detect_tajika_yogas
|
|
r = detect_tajika_yogas({
|
|
'Sun': {'sign': 'Aries', 'degree': 15},
|
|
'Moon': {'sign': 'Aries', 'degree': 18},
|
|
})
|
|
assert len(r) >= 1
|
|
|
|
@test("Tajika vedha detection")
|
|
def t93():
|
|
from tajika import detect_vedha
|
|
r = detect_vedha({
|
|
'Sun': {'degree': 15}, 'Moon': {'degree': 20}, 'Saturn': {'degree': 17},
|
|
})
|
|
assert isinstance(r, list)
|
|
|
|
# ── Prashna tests ──
|
|
@test("Prashna KP answer has confidence")
|
|
def t94():
|
|
from prashna import get_kp_prashna_answer
|
|
r = get_kp_prashna_answer({'Mars': {'sign': 'Aries'}}, 'career', 15.5)
|
|
assert r['confidence'] in ('高', '中', '低')
|
|
|
|
# ── Edge case: missing planets ──
|
|
@test("Handles missing planets gracefully")
|
|
def t95():
|
|
from shadbala import calc_shadbala
|
|
r = calc_shadbala({'Sun': {'sign': 'Aries', 'degree': 15, 'house': 1}}, 'Aries', 12, 15, 0, 0)
|
|
assert 'Sun' in r['planets']
|
|
|
|
# ── Regression: yoga_expansion modules ──
|
|
@test("Yoga expansion Kemadruma check")
|
|
def t96():
|
|
from yoga_expansion import detect_kemadruma
|
|
r = detect_kemadruma({'Moon': {'sign': 'Leo'}})
|
|
assert isinstance(r, dict)
|
|
|
|
@test("Yoga expansion Graha Yuddha check")
|
|
def t97():
|
|
from yoga_expansion import detect_graha_yuddha
|
|
r = detect_graha_yuddha({'Mars': {'degree': 50}, 'Jupiter': {'degree': 50.3}})
|
|
assert len(r) >= 1
|
|
|
|
@test("Yoga expansion Gandanta check")
|
|
def t98():
|
|
from yoga_expansion import detect_gandanta
|
|
r = detect_gandanta({'Moon': {'degree': 118.5}})
|
|
assert isinstance(r, list)
|
|
|
|
# ── Config validation chain ──
|
|
@test("Full validation chain returns confidence")
|
|
def t99():
|
|
from case_validator import validate_interpretation
|
|
interp = {
|
|
'planets': {
|
|
'Saturn': {'dignity': 'debilitated', 'note': '土星落陷需注意'},
|
|
'Jupiter': {'house': 9, 'note': 'Jupiter在9宫有利'},
|
|
}
|
|
}
|
|
r = validate_interpretation(interp)
|
|
assert 'overall_confidence' in r
|
|
|
|
# ── Package integrity ──
|
|
@test("Package version is consistent")
|
|
def t100():
|
|
from jyotish_vedic import __version__
|
|
assert __version__ == '6.9.14'
|
|
|
|
# ── v6.9.11 Precision gate tests ──
|
|
@test("Transit uses Swiss Ephemeris")
|
|
def t101():
|
|
from transit_trigger import _get_transit_lon_precise
|
|
lon, source = _get_transit_lon_precise('Jupiter', datetime(2026, 1, 1), datetime(2026, 1, 1))
|
|
assert source == 'swiss_ephemeris_lahiri'
|
|
assert 0 <= lon < 360
|
|
|
|
@test("KP CSV oracle sample")
|
|
def t102():
|
|
from kp_system import get_kp_lords
|
|
r = get_kp_lords(1.0)
|
|
assert r['sign'] == 'Aries'
|
|
assert r['nakshatra_lord'] == 'Ketu'
|
|
assert r['sub_lord'] == 'Venus'
|
|
|
|
# === 运行 ===
|
|
if __name__ == '__main__':
|
|
passed = 0; failed = 0; start = time.time()
|
|
print(f"\n{'='*50}")
|
|
print(f"🔮 Jyotish Skill Test Suite v1.0 — {len(TESTS)} tests")
|
|
print(f"{'='*50}")
|
|
for name, fn in TESTS:
|
|
try:
|
|
fn()
|
|
passed += 1
|
|
print(f" ✅ {name}")
|
|
except Exception as e:
|
|
failed += 1
|
|
print(f" ❌ {name}: {str(e)[:60]}")
|
|
t = time.time() - start
|
|
print(f"\n{'='*50}")
|
|
print(f" Passed: {passed}/{len(TESTS)} ({passed/len(TESTS)*100:.0f}%)")
|
|
print(f" Failed: {failed}")
|
|
print(f" Time: {t:.1f}s")
|
|
sys.exit(0 if failed == 0 else 1)
|