Files
Jyotisha/tests/run_all.py
T
2026-07-17 11:39:24 +08:00

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)