Files
Jyotisha/tests/run_all.py
T
Jesse_ChenandClaude Opus 5.5 147ebc1789 feat(consult): prompt and Skill read from the evidence card (Skill 6.9.17)
The natal system prompt now says: the card in claim_cards is the chart
evidence for this answer, quote it as given, look up one further section of
this calculation with read-consultation-evidence before writing, and read
evidence_card.backstage as a confidence cap. The "use every executed layer"
and must_use_layers sentences are replaced; local_layers paths now point at
the card. SKILL.md 关联技法完整调取 / 0.0.1 and router 0.7 state that the
full result stays in receipts, the 本轮技法 panel and reports while web chat
answers from the card; computing the full spectrum is unchanged. Skill and
package version 6.9.16 -> 6.9.17 (tests/run_all.py 三栏).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017eEAG8HD3mm8gsKXgk8uU8
2026-09-27 02:54:11 +08:00

732 lines
26 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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__
# 原值=6.9.16;新值=6.9.17。原因=网页普通对话写答案改读数据卡(全谱系计算不变,
# 完整结果留在回执 / 本轮技法 / 报告),SKILL.md「关联技法完整调取」与 0.0.1 同步
# (TASK-consult-evidence-card-20260927 T4)。
assert __version__ == '6.9.17'
# ── 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)